//
//  BattleController.m
//  This file is part of D&D Manager
//
//  Created by Matthew Hutton on 16/02/2007.
//
//
//D&D Manager, a D&D Character and battle management program.
//Copyright (C) 2007, Matthew Hutton
//
//This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License along with this program; if not, write to:
//The Free Software Foundation, Inc.,
//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#import "BattleController.h"
#import "RandomNumbers.h"
#import "FeatActions.h"
#import "AbilityChanged.h"
#import <math.h>
#include <limits.h>
#import "SpellMethods.h"
#import "MyDocument.h"

@implementation BattleController
#pragma mark init
#pragma mark

-(id)initWithBattleStore:(NSManagedObject *)battleCont
		  withMainWindow:(NSWindow *)mainWindow
 withCharacterController:(NSArrayController *)charContMain{
	[super init];
	//NSLog(@"battleController created");
	[NSBundle loadNibNamed:@"Battle"
					 owner:self];
	battleStore=battleCont;
	mainScreen=mainWindow;
	mainCharacterController=charContMain;
	//value transformers.
	damT=[[[Damage alloc] init] autorelease];
	attackB=[[[AttackBonus alloc] init] autorelease];
	wType=[[[WeaponType alloc] init] autorelease];
	cWeap=[[[CurrentWeapon alloc] init] autorelease];
	tyn=[[[ToYesNo alloc] init] autorelease];
	nRang=[[[NotRangedWeapon alloc] init] autorelease];
	lvlOrHD=[[[LevelOrHD alloc] init] autorelease];
	ac=[[[ArmourClass alloc] init] autorelease];
	enableSR=[[[EnableSpellResistance alloc] init] autorelease];
	enableARoll=[[[EnableAttackRollEdit alloc] init] autorelease];
	enableSThrow=[[[EnableSavingThrow alloc] init] autorelease];
	enableDRolls=[[[EnableDiceRolls alloc] init] autorelease];
	[NSValueTransformer setValueTransformer:damT
									forName:@"Damage"];
	[NSValueTransformer setValueTransformer:attackB
									forName:@"AttackBonus"];
	[NSValueTransformer setValueTransformer:wType
									forName:@"WeaponType"];
	[NSValueTransformer setValueTransformer:cWeap
									forName:@"CurrentWeapon"];
	[NSValueTransformer setValueTransformer:tyn
									forName:@"ToYesNo"];
	[NSValueTransformer setValueTransformer:nRang
									forName:@"NotRangedWeapon"];
	[NSValueTransformer setValueTransformer:lvlOrHD
									forName:@"LevelOrHD"];
	[NSValueTransformer setValueTransformer:ac
									forName:@"ArmourClass"];
	[NSValueTransformer setValueTransformer:enableSR
									forName:@"EnableSpellResistance"];
	[NSValueTransformer setValueTransformer:enableARoll
									forName:@"EnableAttackRollEdit"];
	[NSValueTransformer setValueTransformer:enableSThrow
									forName:@"EnableSavingThrow"];
	[NSValueTransformer setValueTransformer:enableDRolls
									forName:@"EnableDiceRolls"];
	attackSheetToDisplayCancel=NO;
	//managedObjectContext.
	mObjC=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
	//NSLog(@"context found");
	model=[[mObjC persistentStoreCoordinator] managedObjectModel];
	return self;
}
-(void)awakeFromNib{
	//[[infoViewInEOR selectedTabViewItem] setView:infoView];
	[featsController setFilterPredicate:nil];
	[featsController setSortDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
	[spellTargetController setSortDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
}
#pragma mark -
#pragma mark Alphabetical
#pragma mark

-(IBAction)addToSurprisedList:(id)sender{
	NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
	//NSLog(@"1");
	//NSLog(@"obj entity=%@",[[obj entity] name]);
	[obj setValue:[NSNumber numberWithBool:YES] forKey:@"surprised"];
	//NSLog(@"2");
	[surprisedCharactersList addObject:obj];
	if([surprisedCharactersList count]>0){
		[removeFromSurprisedButton setEnabled:YES];
	}else{
		[removeFromSurprisedButton setEnabled:NO];
	}
	[surprisedCharactersList sortUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name"
																									   ascending:YES]]];
	[surprisedCharactersTable reloadData];
}
-(IBAction)addFailedToSurprisedList:(id)sender{
	NSArray *array=[[characterController arrangedObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"saveResult CONTAINS \"Fail\""]];
	int i;
	for(i=0;i<[array count];i++){
		NSManagedObject *obj=[array objectAtIndex:i];
		[obj setValue:[NSNumber numberWithBool:YES] forKey:@"surprised"];
		[surprisedCharactersList addObject:obj];
	}
	if([surprisedCharactersList count]>0){
		[removeFromSurprisedButton setEnabled:YES];
	}else{
		[removeFromSurprisedButton setEnabled:NO];
	}
	[addToSurprisedButton setEnabled:NO];
	[surprisedCharactersList sortUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name"
																									   ascending:YES]]];
	[surprisedCharactersTable reloadData];
}
-(NSWindow *)battleScreen{
	return battleScreen;
}
-(IBAction)closePlayerInfoPanel:(id)sender{
	[infoPanel orderOut:self];
	//NSLog(@"to go");
	[NSApp endSheet:infoPanel];
	//NSLog(@"dusted");
}
-(IBAction)closeSurpriseSheet:(id)sender{
	[surprisedCharactersList removeAllObjects];
	[surpriseWindow orderOut:sender];
	[NSApp endSheet:surpriseWindow];
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"disableSurprise"]){
		[battleStore setValue:[NSNumber numberWithInt:0]
					   forKey:@"currentRound"];
	}
	[self beginningOfRoundSetup];
}
-(NSManagedObjectContext *)managedObjectContext{
	if(mObjC==nil){
		mObjC=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
	}
	//return 
	return mObjC;
}
-(void)playerInfoClosed:(NSWindow *)panel
			 returnCode:(int)returnCode
			contextInfo:(NSArray *)info{
	NSWindow *sendersWindow=[info objectAtIndex:0];
	NSManagedObject *toSend=[info objectAtIndex:1];
	[info release];
	if([sendersWindow isSheet]){
		if([sendersWindow isEqualTo:spellTargetSheet]){
			if([mainScreen isVisible]){
				[NSApp beginSheet:sendersWindow
				   modalForWindow:mainScreen
					modalDelegate:self
				   didEndSelector:@selector(spellTargetPanelDidEnd:returnCode:currentSpell:)
					  contextInfo:toSend];
				//NSLog(@"interesting");
			}else{
				[NSApp beginSheet:sendersWindow
				   modalForWindow:battleScreen
					modalDelegate:self
				   didEndSelector:@selector(spellTargetPanelDidEnd:returnCode:currentSpell:)
					  contextInfo:toSend];
				//NSLog(@"this is ok too");
			}
		}else{
			if([mainScreen isVisible]){
				[NSApp beginSheet:sendersWindow
				   modalForWindow:mainScreen
					modalDelegate:self
				   didEndSelector:@selector(featTargetSheetEnded:returnCode:feat:)
					  contextInfo:NULL];
				//NSLog(@"interesting");
			}else{
				[NSApp beginSheet:sendersWindow
				   modalForWindow:battleScreen
					modalDelegate:self
				   didEndSelector:@selector(featTargetSheetEnded:returnCode:feat:)
					  contextInfo:NULL];
				//NSLog(@"this is ok too");
			}
		}
	}
	//NSLog(@"done");
}
-(IBAction)removeFromSurprisedList:(id)sender{
	[surprisedCharactersList removeObjectAtIndex:[surprisedCharactersTable selectedRow]];
	if([surprisedCharactersList count]>0){
		[removeFromSurprisedButton setEnabled:YES];
	}else{
		[removeFromSurprisedButton setEnabled:NO];
	}
	[surprisedCharactersTable reloadData];
}
-(IBAction)rollListenCheck:(id)sender{
	NSArray *chars=[characterController arrangedObjects];
	int i;
	for(i=0;i<[chars count];i++){
		NSManagedObject *obj=[chars objectAtIndex:i];
		NSManagedObject *listenSkill=[[[[obj valueForKey:@"skills"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name==\"Listen\""]] objectAtIndex:0];
		[obj setValue:[AbilityChanged runTestSkill:listenSkill
											 forDC:[surpriseDCBox intValue]]
			   forKey:@"saveResult"];
	}
}
-(IBAction)rollSpotCheck:(id)sender{
	NSArray *chars=[characterController arrangedObjects];
	int i;
	for(i=0;i<[chars count];i++){
		NSManagedObject *obj=[chars objectAtIndex:i];
		NSManagedObject *spotSkill=[[[[obj valueForKey:@"skills"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name==\"Spot\""]] objectAtIndex:0];
		[obj setValue:[AbilityChanged runTestSkill:spotSkill
											 forDC:[surpriseDCBox intValue]]
			   forKey:@"saveResult"];
	}
	
}
-(IBAction)showDicePanel:(id)sender{
	MyDocument *currentDocument=(MyDocument *)[[NSDocumentController sharedDocumentController] currentDocument];
	if(currentDocument==nil){
		currentDocument=(MyDocument *)[[NSApp orderedDocuments] objectAtIndex:0];
		if(currentDocument==nil){
			NSLog(@"currentDocument playing up, and order docs playing up too.");
			NSBeep();
			return;
		}
	}
	[[currentDocument appController] displayRollDiceSheet:nil];
}
-(IBAction)showPlayerInfoPanel:(id)sender{
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];
	if([moreDetailButton state]==NSOffState){
		NSRect rect=[infoPanel frame];
		rect.origin.y=rect.origin.y+213;
		rect.size.height=rect.size.height-213;
		[infoPanel setFrame:rect display:YES];
	}
	if([mainScreen isVisible]){
		[NSApp beginSheet:infoPanel
		   modalForWindow:mainScreen
			modalDelegate:self
		   didEndSelector:nil
			  contextInfo:NULL];
	}else{
		[NSApp beginSheet:infoPanel
		   modalForWindow:battleScreen
			modalDelegate:self
		   didEndSelector:nil
			  contextInfo:NULL];
	}
}
-(IBAction)showPlayerInfoPanelFromSpellsOrFeats:(id)sender{
	NSWindow *sendersWindow=[sender window];
	[sendersWindow orderOut:self];
	if([moreDetailButton state]==NSOffState){
		NSRect rect=[infoPanel frame];
		rect.origin.y=rect.origin.y+213;
		rect.size.height=rect.size.height-213;
		[infoPanel setFrame:rect display:YES];
	}
	[NSApp endSheet:sendersWindow returnCode:2];
}
//end alphabetical ordering.
-(IBAction)showMoreInfoDetail:(id)sender{
	NSWindow *window=[sender window];
	NSRect rect=[window frame];
	if([sender state]==NSOnState){
		rect.size.height=rect.size.height+213;
		rect.origin.y=rect.origin.y-213;
		[moreInfoBox setHidden:NO];
	}else{
		rect.origin.y=rect.origin.y+213;
		rect.size.height=rect.size.height-213;
		[moreInfoBox setHidden:YES];	
	}
	[window setFrame:rect display:YES];
}
-(IBAction)showMoreInfoDetailEOR:(id)sender{
	NSWindow *window=[sender window];
	NSRect rect=[window frame];
	if([sender state]==NSOnState){
		rect.size.height=rect.size.height+222;
		rect.origin.y=rect.origin.y-222;
		[moreInfoBox2 setHidden:NO];
	}else{
		rect.origin.y=rect.origin.y+222;
		rect.size.height=rect.size.height-222;
		[moreInfoBox2 setHidden:YES];	
	}
	[window setFrame:rect display:YES];
}
#pragma mark -
#pragma mark Starting, Ending and Continuing Battle.
#pragma mark

//starting battle.
-(void)battleNewSet{
	NSString *message=@"";
	if([[battleStore valueForKey:@"continueBattle"] boolValue]){
		message=[self battleExitSet:NO];
		if(![message isEqualToString:@""]){
			[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
						   forKey:@"eventLog"];
			NSBeginInformationalAlertSheet(@"Event's Result", @"Continue", nil, nil, mainScreen, self, nil, @selector(previousExitingSheetEnded:returnCode:contextInfo:), NULL,message);
			return;
		}
	}
	[self battleNewSet2];
}
-(void)previousExitingSheetEnded:(NSWindow *)sheet
					  returnCode:(int)returnCode
					 contextInfo:(void  *)contextInfo{
	[self battleNewSet2];
}
-(void)battleNewSet2{
	[self newAndContinueSetupIsNew:YES
						isSummoned:NO
					   activeSpell:nil];
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"disableSurprise"]){
		//reset round number.
		[battleStore setValue:[NSNumber numberWithInt:0]
					   forKey:@"currentRound"];
		[self beginningOfRoundSetup];
	}else{
		//reset round number.
		[battleStore setValue:[NSNumber numberWithInt:-1]
					   forKey:@"currentRound"];
		int i;
		NSArray *chars=[characterController arrangedObjects];
		for(i=0;i<[chars count];i++){
			[[chars objectAtIndex:i] setValue:@"" forKey:@"saveResult"];
		}
		//[surprisedCharactersList setArray:[[characterController arrangedObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"surprised==1"]]];
		//[surprisedCharactersList sortUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name"
		//															ascending:YES]]];
		if(surprisedCharactersList==nil){
			surprisedCharactersList=[[NSMutableArray alloc] initWithCapacity:1];
		}
		[surprisedCharactersList removeAllObjects];
		[surprisedCharactersTable reloadData];
		[NSApp beginSheet:surpriseWindow
		   modalForWindow:battleScreen
			modalDelegate:self
		   didEndSelector:nil
			  contextInfo:NULL];
	}
	//NSLog(@"battleNewSet Finished");
}
-(void)battleContinueSet{
	//NSLog(@"continuing battle");
	BOOL summoned=[[battleStore valueForKey:@"returnedFromSummoning"] boolValue];
	NSManagedObject *activeSpell=nil;
	if(summoned){
		activeSpell=[[[battleStore valueForKey:@"activeSpell"] allObjects] objectAtIndex:0];
		[battleStore setValue:nil
					   forKey:@"activeSpell"];
	}
	[self newAndContinueSetupIsNew:NO
						isSummoned:summoned
					   activeSpell:activeSpell];
	[battleStore setValue:[NSNumber numberWithBool:NO]
				   forKey:@"editingAtEOR"];
	//disable summoned
	[battleStore setValue:[NSNumber numberWithBool:NO]
				   forKey:@"returnedFromSummoning"];
	if([[battleStore valueForKey:@"editingAtEOR"] boolValue]){
		[self beginningOfRoundSetup];
	}else{
		int cr=[[battleStore valueForKey:@"currentRound"] intValue];
		if(cr==0){
			[battleScreen setTitle:@"Surprise Round"];
		}else{
			[battleScreen setTitle:[NSString stringWithFormat:@"Round %d",cr]];
		}
		//processing some beginning of round stuff.
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember==1 OR enemyPartyMember==1"]];
		NSArray *activeChars=[characterController arrangedObjects];
		[battleStore setValue:[NSNumber numberWithInt:[activeChars count]]
					   forKey:@"numberOfActiveChars"];
		//NSLog(@"noOfActiveChars=%d",[[battleStore valueForKey:@"numberOfActiveChars"] intValue]);
		[battleStore setValue:[[activeChars objectAtIndex:0] valueForKey:@"initiative"]
					   forKey:@"currentInitiative"];
		[battleStore setValue:[NSNumber numberWithInt:0]
					   forKey:@"currentCharacter"];
		[self setupBattleDisplayWithMessage:nil];
	}
	//NSLog(@"battleContinueSetFinished");
}
-(void)newAndContinueSetupIsNew:(BOOL)isNew
					 isSummoned:(BOOL)summoned
					activeSpell:(NSManagedObject *)activeSpell{
	//NSLog(@"new and continuing battle setup");
	//new stuff
	mObjC=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
	model=[[mObjC persistentStoreCoordinator] managedObjectModel];
	//end new stuff.
	//reset predicates.
	[characterController setFilterPredicate:nil];
	if([[characterController arrangedObjects] count]==0){
		NSLog(@"no characters, adding from context.");
		[characterController addObjects:[mainCharacterController arrangedObjects]];
	}
	//[spellController setFilterPredicate:nil];
	//[weaponController setFilterPredicate:nil];
	//[skillsController setFilterPredicate:nil];
	//[featsController setFilterPredicate:nil];
	//initial display setup
	[mainTabs selectTabViewItemAtIndex:1];
	[currentlyBusy startAnimation:self];
	[battleScreen makeKeyAndOrderFront:self];
	MyDocument *currentDocument=(MyDocument *)[[NSDocumentController sharedDocumentController] currentDocument];
	if(currentDocument==nil){
		currentDocument=(MyDocument *)[[NSApp orderedDocuments] objectAtIndex:0];
		if(currentDocument==nil){
			NSLog(@"currentDocument playing up, and order docs playing up too.");
			NSBeep();
			return;
		}
	}
	[currentDocument addWindowController:self];
	[mainScreen orderOut:self];
	[(MenuController *)[NSApp delegate] enableDiceAndLogButtons];
	[(MenuController *)[NSApp delegate] exitBattleNowOn:YES];
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];
	NSArray *characters=[characterController arrangedObjects];
	//reseed numbers
	[RandomNumbers reseedRandomNumbers];
	int i;
	for(i=0;i<[characters count];i++){
		NSManagedObject *obj=[characters objectAtIndex:i];
		//NSLog(@"getting ready to process %@",[obj valueForKey:@"name"]);
		if(isNew || [obj valueForKey:@"initiative"]==nil){
			//NSLog(@"processing %@",[obj valueForKey:@"name"]);
			[self processForBattleTheChar:obj
							   isSummoned:summoned
						   forActiveSpell:activeSpell];
		}
	}
	//now begin combat.
	[characterController setSortDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
	[characterController rearrangeObjects];
}
-(void)processForBattleTheChar:(NSManagedObject *)obj
					isSummoned:(BOOL)summoned
				forActiveSpell:(NSManagedObject *)activeSpell{
	int bonus=[[obj valueForKey:@"initiativeBonus"] intValue];
	int score=[RandomNumbers randomIntUpTo:20];
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
		NSString *message=[NSString stringWithFormat:@"\nRolled a %d+%d for %@'s initiative",score,bonus,[obj valueForKey:@"name"]];
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
					   forKey:@"eventLog"];
	}
	int init=score+bonus;
	[obj setValue:[NSNumber numberWithInt:init]
		   forKey:@"initiative"];
	//Set flat footed.
	[obj setValue:[NSNumber numberWithBool:YES]
		   forKey:@"flatFooted"];
	[obj setValue:[NSNumber numberWithBool:YES]
		   forKey:@"firstRoundInCombat"];
	//some basic character setup.
	[obj setValue:[obj valueForKey:@"noOfAttacks"]
		   forKey:@"attacksLeftThisRound"];
	[obj setValue:[obj valueForKey:@"maxAttackOO"]
		   forKey:@"attackOOLeftThisRound"];
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"processedThisTurn"];
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"healthCheckedThisRound"];
	if([obj valueForKey:@"currentHP"]==nil){//character has no current hp value.
		[obj setValue:[NSNumber numberWithInt:1]
			   forKey:@"currentHP"];
	}
	if([obj valueForKey:@"maxHP"]==nil){//character has no max hp value.
		[obj setValue:[NSNumber numberWithInt:1]
			   forKey:@"maxHP"];
	}
	//create active feats as required.
	NSArray *feats=[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"active==1 AND (lastsForever==0 OR featAffects != 0)"]];
	int j;
	for(j=0;j<[feats count];j++){
		NSManagedObject *feat=[feats objectAtIndex:j];
		NSManagedObject *activeFeat=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"ActiveFeat"]
											 insertIntoManagedObjectContext:mObjC];
		if([[feat valueForKey:@"runsUntilBattleEnded"] boolValue] || [[feat valueForKey:@"lastsForever"] boolValue]){
			[activeFeat setValue:[NSNumber numberWithInt:0]
						  forKey:@"lastsUntilRound"];
		}else{
			[activeFeat setValue:[NSNumber numberWithInt:[[feat valueForKey:@"timeLastsFor"] intValue]+1]
						  forKey:@"lastsUntilRound"];
		}
		[activeFeat setValue:feat
					  forKey:@"feat"];
		[activeFeat setValue:obj
					  forKey:@"caster"];
	}
	if(summoned){//so summoned monster is added as a target.
		NSMutableSet *set=[activeSpell valueForKey:@"target"];
		[set addObject:obj];
		[obj setValue:[NSNumber numberWithBool:YES]
			   forKey:@"summoned"];
		[activeSpell setValue:set
					   forKey:@"target"];
	}
}
-(IBAction)exitBattleMode:(id)sender{
	NSString *message=[self battleExitSet:YES];
	if(![message isEqualToString:@""]){
		//log message.
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
					   forKey:@"eventLog"];
		NSBeginInformationalAlertSheet(@"Event's Result", @"Continue", nil, nil, mainScreen, self,nil,nil,NULL,message);
	}
}
-(NSString *)battleExitSet:(BOOL)deleteOldChars{
	NSLog(@"actually exiting battle, deleting oldChars=%d",deleteOldChars);
	//remove charge changes as required.
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];//reset display.
	NSArray *activeChars=[characterController arrangedObjects];
	NSString *message=@"";
	int i;
	for(i=0;i<[activeChars count];i++){
		NSManagedObject *obj=[activeChars objectAtIndex:i];
		message=[self processForExitTheCharacter:obj
									 withMessage:message];
	}
	if([battleScreen isVisible]){
		[battleScreen orderOut:self];
		[self close];
		//display main screen
		[mainScreen makeKeyAndOrderFront:self];
	}
	if(deleteOldChars){
		//NSLog(@"hi");
		//delete temporary characters.
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"(mainPartyMember == 1 OR enemyPartyMember == 1)"]];
		//NSLog(@"hi+1");
		NSArray *array=[[characterController arrangedObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"temp == 1"]];
		//NSLog(@"temps count=%d",[array count]);
		for(i=0;i<[array count];i++){
			[mObjC deleteObject:[array objectAtIndex:i]];
		}		
	}
	//delete current events.
	NSArray *currentEvents=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"currentEvent" substitutionVariables:[NSDictionary dictionary]]
												 error:nil];
	for(i=0;i<[currentEvents count];i++){
		[mObjC deleteObject:[currentEvents objectAtIndex:i]];
	}
	[characterController rearrangeObjects];
	[mainCharacterController rearrangeObjects];
	//no battle running.
	[battleStore setValue:[NSNumber numberWithBool:NO]
				   forKey:@"continueBattle"];
	//disable buttons too.
	[(MenuController *)[NSApp delegate] continueBattleNowOn:NO];
	[(MenuController *)[NSApp delegate] exitBattleNowOn:NO];
		//reset predicates.
	[characterController setFilterPredicate:nil];
	[characterController rearrangeObjects];
	[mainCharacterController rearrangeObjects];
	//NSLog(@"message to return");
	return message;
	//[spellController setFilterPredicate:nil];
	//[weaponController setFilterPredicate:nil];
	//[skillsController setFilterPredicate:nil];
	//[featsController setFilterPredicate:nil];
}
-(void)beginningOfRoundSetup{
	//NSLog(@"starting round setup");
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];//reset display.
	NSArray *activeChars=[characterController arrangedObjects];
	[battleStore setValue:[NSNumber numberWithInt:[activeChars count]]
				   forKey:@"numberOfActiveChars"];
	int cr=[[battleStore valueForKey:@"currentRound"] intValue]+1;
	[battleStore setValue:[NSNumber numberWithInt:cr]
				   forKey:@"currentRound"];
	if(cr==0){
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n\n********** Surprise Round **********",cr]
					   forKey:@"eventLog"];
			[battleScreen setTitle:@"Surprise Round"];
	}else{
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n\n********** Round %d **********",cr]
					   forKey:@"eventLog"];
			[battleScreen setTitle:[NSString stringWithFormat:@"Round %d",cr]];
	}
	//set attackOO to zero.
	int i;
	for(i=0;i<[activeChars count];i++){
		NSManagedObject *obj=[activeChars objectAtIndex:i];
		[obj setValue:[obj valueForKey:@"noOfAttacks"]
			   forKey:@"attacksLeftThisRound"];
		[obj setValue:[obj valueForKey:@"maxAttackOO"]
			   forKey:@"attackOOLeftThisRound"];
		[obj setValue:[NSNumber numberWithBool:NO]
			   forKey:@"processedThisTurn"];
		[obj setValue:[NSNumber numberWithBool:NO]
			   forKey:@"healthCheckedThisRound"];
		//disable processedThisTurn for events.
		NSArray *events=[[obj valueForKey:@"casterOfCurrentEvent"] allObjects];
		int j;
		for(j=0;j<[events count];j++){
			[[events objectAtIndex:j] setValue:[NSNumber numberWithBool:NO]
										forKey:@"processedThisTurn"];
		}
		events=[[obj valueForKey:@"casterOfActiveEvent"] allObjects];
		for(j=0;j<[events count];j++){
			[[events objectAtIndex:j] setValue:[NSNumber numberWithBool:NO]
										forKey:@"processedThisTurn"];
		}

	}
	//[theArray release];
	//[buttonsAtBottomView selectTabViewItemAtIndex:0];
	//set window size back to default.
	//NSSize frameSize;
	//frameSize.height=567;
	//frameSize.width=540;
	//[battleScreen setContentSize:frameSize];
	if([activeChars count]==0){
		NSLog(@"no characters for battle.");
	}
	[battleStore setValue:[[activeChars objectAtIndex:0] valueForKey:@"initiative"]
				   forKey:@"currentInitiative"];
	[battleStore setValue:[NSNumber numberWithInt:0]
				   forKey:@"currentCharacter"];
	//setting up multi-attack settings.
	[battleStore setValue:[NSNumber numberWithInt:0]
				   forKey:@"subround"];
	//process feats to set value of NO for target check.
	NSArray *feats=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"featsWithTargets" substitutionVariables:[NSDictionary dictionary]]
										error:nil];
	for(i=0;i<[feats count];i++){
		[[feats objectAtIndex:i] setValue:[NSNumber numberWithBool:NO]
								   forKey:@"featTargetChosenThisRound"];
	}
	[self setupBattleDisplayWithMessage:nil];//now displaying first character data.
	//NSLog(@"beginningOfRoundSetup complete");
}
#pragma mark -
#pragma mark SetupBattleDisplay
#pragma mark
-(void)setupBattleDisplayWithMessage:(NSString *)message{
	//NSLog(@"displaying battle display.");
	//NSLog(@"eventLog=%@",[battleStore valueForKey:@"eventLog"]);
	if(!([message isEqualToString:@""] || message==nil)){
		//log message.
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
					   forKey:@"eventLog"];
		if([mainScreen isVisible]){
			NSBeginInformationalAlertSheet(@"Results",@"Continue",nil,nil,mainScreen,self,nil, @selector(alertFromEventDidEnd:returnCode:contextInfo:),NULL,message);
		}else{
			NSBeginInformationalAlertSheet(@"Results",@"Continue",nil,nil,battleScreen,self,nil, @selector(alertFromEventDidEnd:returnCode:contextInfo:),NULL,message);
		}
		//NSLog(@"displaying message (set up battle display...)");
		return;
	}
	//now check if any messages in currentAttacks.
	NSArray *eventsWithMessages=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"eventWithAMessage" substitutionVariables:[NSDictionary dictionary]]
										error:nil];
	if([eventsWithMessages count]>0){
		NSManagedObject *ce=[eventsWithMessages objectAtIndex:0];
		NSString *message=[ce valueForKey:@"resultMessage"];
		if([mainScreen isVisible]){
			NSBeginInformationalAlertSheet(@"Results",@"Continue",@"Edit",nil,mainScreen,self,nil, @selector(alertFromCurrentEventDidEnd:returnCode:contextInfo:),ce,message);
		}else{
			NSBeginInformationalAlertSheet(@"Results",@"Continue",@"Edit",nil,battleScreen,self,nil, @selector(alertFromCurrentEventDidEnd:returnCode:contextInfo:),ce,message);
		}
		return;
	}
	//exit here if main screen is visible.
	if([mainScreen isVisible]){
		return;
	}
	if([[battleStore valueForKey:@"currentCharacter"] intValue]>=[[battleStore valueForKey:@"numberOfActiveChars"] intValue]){
		//NSLog(@"EOR");
		//check whether we have actually reached the end of the round.
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"attacksLeftThisRound > 0 AND (mainPartyMember == 1 OR enemyPartyMember == 1)"]];
		//int i;
		//NSArray *array=[characterController arrangedObjects];
		/*for(i=0;i<[array count];i++){
			//NSLog(@"%@ has attacks left.",[[array objectAtIndex:i] valueForKey:@"name"]);
		}*/
		//so if more than 100 attacks not all are carried out. (100 is a crazy number of attacks anyway).
		if([[characterController arrangedObjects] count]==0 || [[battleStore valueForKey:@"subround"] intValue]>100){
			[self endRound:nil];
		}else{
			//NSLog(@"next subround");
			[battleStore setValue:[NSNumber numberWithInt:0]
						   forKey:@"currentCharacter"];
			[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"subround"] intValue]+1)]
						   forKey:@"subround"];
		}
	}
	if([self runCurrentAttacks]){
		//NSLog(@"running CurrentAttacks");
		return;
	}
	NSManagedObject *obj=[self currentCharacter];
	//NSLog(@"obj=%@",[obj valueForKey:@"name"]);
	if(!([[battleStore valueForKey:@"currentInitiative"] intValue]==[[obj valueForKey:@"initiative"] intValue])){
		//NSLog(@"running attacks and standard action spells");
		//if spells to cast then cast them
		if([self runCurrentSpells]){
			//NSLog(@"running CurrentSpells");
			return;
		}
		//afterwards.
		[battleStore setValue:[obj valueForKey:@"initiative"]
					   forKey:@"currentInitiative"];
	}
	BOOL firstGo=YES;
	//check if surprised round and surprised.
	if([[battleStore valueForKey:@"currentRound"] intValue]==0 && [[obj valueForKey:@"surprised"] boolValue]){
		//character not going now, skipping.
		[obj setValue:[NSNumber numberWithInt:0]
			   forKey:@"attacksLeftThisRound"];
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		//NSLog(@"%@ suprised",[obj valueForKey:@"name"]);
		[self setupBattleDisplayWithMessage:nil];
		return;
	}
	//no attacks left so should return.
	if([[obj valueForKey:@"attacksLeftThisRound"] intValue]==0){
		//NSLog(@"%@ has no attacks left.",[obj valueForKey:@"name"]);
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		[self setupBattleDisplayWithMessage:nil];
		return;
	}
	if([[obj valueForKey:@"noOfAttacks"] intValue]!=[[obj valueForKey:@"attacksLeftThisRound"] intValue]){
		if([[battleStore valueForKey:@"subround"] intValue]<([[obj valueForKey:@"noOfAttacks"] intValue]-[[obj valueForKey:@"attacksLeftThisRound"] intValue])){
			//character not going now, skipping.
			//NSLog(@"%@ skipping (subround wrong)",[obj valueForKey:@"name"]);
			[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
						   forKey:@"currentCharacter"];
			[self setupBattleDisplayWithMessage:nil];
			return;
		}
		firstGo=NO;
	}
	//NSLog(@"about to check turning");
	//check if turned.
	if([[obj valueForKey:@"turned"] boolValue]){
		NSBeginInformationalAlertSheet(@"Character Currently Turned",@"Skip to next", @"Break Turning",nil ,battleScreen,self, nil,@selector(alertFromTurningDidEnd:returnCode:contextInfo:),NULL,[NSString stringWithFormat:@"This character (%@) is currently turned",[obj valueForKey:@"name"]]);
		return;
	}
	//regeneration.
	if(firstGo && ![[obj valueForKey:@"healthCheckedThisRound"] boolValue]){
		int reg=[[obj valueForKey:@"regeneration"] intValue];
		//set to stable if regenerates.
		if(reg>0){
			[obj setValue:[NSNumber numberWithBool:YES]
				   forKey:@"stable"];
			//does regeneration (as required).
			int currentHP=[[obj valueForKey:@"currentHP"] intValue];
			if(reg+currentHP>[[obj valueForKey:@"maxHP"] intValue]){
				[obj setValue:[obj valueForKey:@"maxHP"]
					   forKey:@"currentHP"];
			}else{
				[obj setValue:[NSNumber numberWithInt:reg+currentHP]
					   forKey:@"currentHP"];
			}
		}
	}
	//NSLog(@"about to check if active");
	//check if active (by HP).
	NSArray *feats=[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"active==1 AND type==3 AND miscUse==\"Conscious for Negative HP\" AND ability==0"]];
	if([[obj valueForKey:@"currentHP"] intValue]<=0 && !([feats count]>0) && ![[obj valueForKey:@"healthCheckedThisRound"] boolValue]){
		//check if unconcious.
		if([[obj valueForKey:@"currentHP"] intValue]<0){
			//check if stable.
			if([[obj valueForKey:@"stable"] boolValue]==NO && ![[obj valueForKey:@"healthCheckedThisRound"] boolValue]){
				int result=[RandomNumbers randomIntUpTo:10];
				if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
					NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d to check %@'s stability (a 10 required to become stable).",result,[obj valueForKey:@"name"]];
					[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
								   forKey:@"eventLog"];
				}
				if(result==10){
					NSString *newMessage=[NSString stringWithFormat:@"\n%@ has now stabilized.",[obj valueForKey:@"name"]];
					[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
								   forKey:@"eventLog"];
					[obj setValue:[NSNumber numberWithBool:YES]
						   forKey:@"stable"];
				}else{
					[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"currentHP"] intValue]-1)]
						   forKey:@"currentHP"];
					NSString *newMessage=[NSString stringWithFormat:@"\n%@ is still dying and now has %@ hit points.",[obj valueForKey:@"name"],[obj valueForKey:@"currentHP"]];
					[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
								   forKey:@"eventLog"];
				}
			}
		}
		[obj setValue:[NSNumber numberWithBool:YES]
			   forKey:@"healthCheckedThisRound"];
		NSString *message2=[self deathCheck:obj];
		[self setupBattleDisplayWithMessage:message2];
		//NSLog(@"%@ is dead",[obj valueForKey:@"name"]);
		return;
	}
	[obj setValue:[NSNumber numberWithBool:YES]
		   forKey:@"healthCheckedThisRound"];
	//NSLog(@"processing active spells etc. etc.");
	if(firstGo && ![[obj valueForKey:@"processedThisTurn"] boolValue]){
		//check if concentrating.
		NSArray *activeEvents=[[obj valueForKey:@"casterOfActiveEvent"] allObjects];

		//now process first turn in round only stuff.
		//checking charged.
		if([[obj valueForKey:@"charged"] boolValue]){
			[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]-2]
				   forKey:@"meleeMiscBonus"];
			[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassTotal"] intValue]+2]
				   forKey:@"armourClassTotal"];
			[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassFlat"] intValue]+2]
				   forKey:@"armourClassFlat"];
			[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassTouch"] intValue]+2]
				   forKey:@"armourClassTouch"];
			[obj setValue:[NSNumber numberWithBool:NO]
				   forKey:@"charge"];
		}
		//now checking current spells for the character (ct>=1rd)
		NSArray *events=[[obj valueForKey:@"casterOfCurrentEvent"] allObjects];
		//NSLog(@"events cast.count=%d",[events count]);
		int i;
		for(i=0;i<[events count];i++){
			NSManagedObject *event=[events objectAtIndex:i];
			if(![[event entity] isEqualTo:[[model entitiesByName]  objectForKey:@"CurrentSpell"]]){
				continue;
			}
			if([[[[event valueForKey:@"spellClass"] valueForKey:@"spell"] valueForKey:@"castingTime"] intValue]<=1){
				continue;
			}
			NSManagedObject *spell=[[event valueForKey:@"spellClass"] valueForKey:@"spell"];
			//one round spell or spell ready to cast.
			if([[spell valueForKey:@"castingTime"] intValue]==2 || [[event valueForKey:@"runsOutInRound"] intValue]==[[battleStore valueForKey:@"currentRound"] intValue]){
				[self runSpellWithCurrentSpell:event];
				//NSLog(@"%@ running spell to cast",[obj valueForKey:@"name"]);
				return;
			}else if(![[event valueForKey:@"processedThisTurn"] boolValue]){
				//roll conc for spells still casting.
				NSString *message2;
				if([self rollConcentrationForCurrentSpell:event]){
					message2=[NSString stringWithFormat:@"%@ has passed a concentration check on the spell %@",[obj valueForKey:@"name"],[spell valueForKey:@"name"]];
					[event setValue:[NSNumber numberWithBool:YES]
							 forKey:@"processedThisTurn"];
				}else{
					message2=[NSString stringWithFormat:@"%@ has failed a concentration check on the spell %@, casting has been cancelled.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]];
					[mObjC deleteObject:event];
				}
				[self setupBattleDisplayWithMessage:message2];
				//NSLog(@"returning event message to show");
				return;
			}
		}
		//kill old current events.
		events=[[[obj valueForKey:@"casterOfCurrentEvent"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"runsOutInRound == %d OR lastsMultipleRounds == 0",[[battleStore valueForKey:@"currentRound"] intValue]]]];
		for(i=0;i<[events count];i++){
			[mObjC deleteObject:[events objectAtIndex:i]];
		}
		//looking at active events.
		for(i=0;i<[activeEvents count];i++){
			NSManagedObject *activeEvent=[activeEvents objectAtIndex:i];
			if([[activeEvent valueForKey:@"processedThisTurn"] boolValue])
				continue;
			[activeEvent setValue:[NSNumber numberWithBool:YES]
						   forKey:@"processedThisTurn"];
			if([[activeEvent entity] isEqualTo:[[model entitiesByName]  objectForKey:@"ActiveSpell"]]){
				NSManagedObject *spell=[activeEvent valueForKey:@"spell"];
				//check whether spell concentrates and whether the spell caster decided to concentrate at the end of the spell casting.
				if([[spell valueForKey:@"durForConc"] boolValue] && [[activeEvent valueForKey:@"isConcentrating"] boolValue]){
					//check concentration and check if can concentrate any longer.
					if([self rollConcentrationForCharacter:obj
											 forSpellLevel:[[activeEvent valueForKey:@"spellLevel"] intValue]] && [[spell valueForKey:@"durMaxConc"] intValue]>[[activeEvent valueForKey:@"hasConcentratedFor"] intValue]){
						NSBeginInformationalAlertSheet(@"Concentration",@"Concentrate",@"Break Concentration",nil,battleScreen,self,nil, @selector(alertFromConcCheckDidEnd:returnCode:activeEvent:),activeEvent,[NSString stringWithFormat:@"%@ is concentration on the spell %@, do you wish to continue?",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]);
						return;
					}else{
						//not concentrating no more.
						[activeEvent setValue:[NSNumber numberWithBool:NO]
									   forKey:@"isConcentrating"];
					}
				}
				NSString *message2=[self checkTheActiveSpell:activeEvent];
				//do nothing if message is nil as proper target sheet shown.
				if(message2!=nil){
					[self setupBattleDisplayWithMessage:message2];
				}else{
					
				}
				//NSLog(@"active events so returning");
				return;
			}
		}
		//NSLog(@"about to kill active events");
		//kill active events as required.
		events=[[[obj valueForKey:@"casterOfActiveEvent"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"lastsUntilRound <= %d AND lastsUntilRound !=0",[[battleStore valueForKey:@"currentRound"] intValue]]]];
		//kill active events as required.
		NSString *message2=@"";
		//create message to display as active events die (and kill them)
		for(i=0;i<[events count];i++){
			NSManagedObject *event=[events objectAtIndex:i];
			message2=[self killTheActiveEvent:event
								withCharacter:obj
									withMessage:message2
							  toExit:NO];
		}
		//display the message.
		//NSLog(@"message to show l882");
		if(![message2 isEqualToString:@""]){
			[self setupBattleDisplayWithMessage:message2];
			return;
		}
	}
	//NSLog(@"ready to exit if paralysed.");
	//exit if slowed (and no turn) or paralysed.
	if([[obj valueForKey:@"paralysed"] intValue]>0){
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		[obj setValue:[NSNumber numberWithInt:0]
			   forKey:@"attacksLeftThisRound"];
		[self setupBattleDisplayWithMessage:nil];
		//NSLog(@"%@ paralysed",[obj valueForKey:@"name"]);
		return;
	}
	//NSLog(@"setting up targets for feats");
	if(firstGo && ![[obj valueForKey:@"processedThisTurn"] boolValue]){
		//display target sheet for feats
		NSArray *feats=[[[obj valueForKey:@"feats"] allObjects]  filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"featAffects != 0"]];
		int i;
		for(i=0;i<[feats count];i++){
			//NSLog(@"processing feats");
			NSManagedObject *feat=[feats objectAtIndex:i];
			//check if feat needs processing.
			if([[feat valueForKey:@"featTargetChosenThisRound"] boolValue]==NO && ([[obj valueForKey:@"firstRoundInCombat"] boolValue] || [feat valueForKey:@"target"]==nil || [[feat valueForKey:@"targetChangesEachRound"] boolValue])){
				[feat setValue:[NSNumber numberWithBool:YES]
						forKey:@"featTargetChosenThisRound"];
				//display target window.
				[self displayFeatTargetSheetByChar:obj
										   forFeat:feat];
				//NSLog(@"feat target to show");
				return;
			}
		}
		//reactivates the feat cleave (as required).
		[obj setValue:[NSNumber numberWithBool:NO]
			   forKey:@"cleaveUsedThisRound"];
	}
	//if the character already has no attacks remaining (is concentrating) skip.
	if([[obj valueForKey:@"attacksLeftThisRound"] intValue]==0){
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		[self setupBattleDisplayWithMessage:nil];
		//NSLog(@"%@ no attacks left.",[obj valueForKey:@"name"]);
		return;
	}
	//NSLog(@"setting up blurb/portrait.");
	//set up blurb/portrait.
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];//reset display.
	//turn off flat footed.
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"flatFooted"];
	NSData *portrait=[[obj valueForKey:@"portraitObject"] valueForKey:@"portraitData"];
	if(!portrait==nil){
		[characterPortrait setHidden:NO];
		[characterPortrait setImage:[[NSImage alloc] initWithData:portrait]];
	}else{
		[characterPortrait setImage:nil];
	}
	//sets that we have processed this turn.
	[obj setValue:[NSNumber numberWithBool:YES]
		   forKey:@"processedThisTurn"];
	[turnDescription setStringValue:[self createBlurbForCharacter:obj]];
	[mainTabs selectTabViewItemAtIndex:0];
	//DISABLING FirstRoundInCombat
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"firstRoundInCombat"];
	//NSLog(@"shortcut setup");
	if(firstGo){
		//check which tabs to display.
		if([optionTabs indexOfTabViewItem:[optionTabs selectedTabViewItem]]==5){
			[optionTabs selectTabViewItemAtIndex:0];
		}
	}else{
		//check which tabs to display.
		[optionTabs selectTabViewItemAtIndex:5];
	}
	[self processOptionTabsForTabViewItem:[optionTabs selectedTabViewItem]];
	//NSLog(@"setupBattleDisplay finished");
}
-(NSString *)createBlurbForCharacter:(NSManagedObject *)obj{
	NSMutableString *blurb=[[NSMutableString alloc] initWithCapacity:10];
	//check gender
	NSString *gender=[AbilityChanged getGenderOfCharacter:obj];
	[blurb appendFormat:@"It is now %@'s turn, %@ currently has %d out of %d hit points and an initiative of %d",[obj valueForKey:@"name"],gender,[[obj valueForKey:@"currentHP"] intValue],[[obj valueForKey:@"maxHP"] intValue],[[obj valueForKey:@"initiative"] intValue]];
	//check whether using two weapons.
	int attackCount=0;
	if([[obj valueForKey:@"usesWeapons"] boolValue]){
		attackCount=[[obj valueForKey:@"noOfAttacks"] intValue];
		NSManagedObject *weap=[obj valueForKey:@"defaultWeapon"];
		if([[obj valueForKey:@"usesTwoWeapons"] boolValue]){
			NSManagedObject *weap2=[obj valueForKey:@"offWeapon"];
			[blurb appendFormat:@", %@ is currently using a %@ doing %@ damage with %@ to hit and a %@ doing %@ damage with %@ to hit",gender,[weap valueForKey:@"name"],[damT transformedValue:weap],[attackB transformedValue:weap],[weap2 valueForKey:@"name"],[damT transformedValue:weap2],[attackB transformedValue:weap2]];
			attackCount++;
		}else{
			[blurb appendFormat:@", %@ is currently using a %@ doing %@ damage with %@ to hit",gender,[weap valueForKey:@"name"],[damT transformedValue:weap],[attackB transformedValue:weap]];
		}
		attackCount=attackCount+([[weap valueForKey:@"noOfSimultaneousAttacks"] intValue]-1);
	}else{
		attackCount=0;
		NSArray *array=[[obj valueForKey:@"weapons"] allObjects];
		if([array count]==0){
			[blurb appendFormat:@" %@ is currently not using any weapons."];
		}else{
			[blurb appendFormat:@" %@ is currently using ",gender];
			int i;
			for(i=0;i<[array count];i++){
				NSManagedObject *weap=[array objectAtIndex:i];
				NSString *name;
				if([[weap valueForKey:@"noOfSimultaneousAttacks"] intValue]==1){
					name=[NSString stringWithFormat:@"%@ once",[weap valueForKey:@"name"]];
					attackCount++;
				}else if([[weap valueForKey:@"noOfSimultaneousAttacks"] intValue]==2){
					name=[NSString stringWithFormat:@"%@ twice",[weap valueForKey:@"name"]];
					attackCount+=2;
				}else{
					name=[NSString stringWithFormat:@"%@ %dx",[weap valueForKey:@"name"],[[weap valueForKey:@"noOfSimultaneousAttacks"] intValue]];
					attackCount+=[[weap valueForKey:@"noOfSimultaneousAttacks"] intValue];
				}
				if(i+1==[array count]){
					if(i==0){
						[blurb appendFormat:@"a %@ doing %@ damage with %@ to hit",name,[damT transformedValue:weap],[attackB transformedValue:weap]];
					}else{
						[blurb appendFormat:@"and a %@ doing %@ damage with %@ to hit",name,[damT transformedValue:weap],[attackB transformedValue:weap]];
					}
				}else{
					if(i+2==[array count]){
						[blurb appendFormat:@"a %@ doing %@ damage with %@ to hit ",name,[damT transformedValue:weap],[attackB transformedValue:weap]];
					}else{
						[blurb appendFormat:@"a %@ doing %@ damage with %@ to hit, ",name,[damT transformedValue:weap],[attackB transformedValue:weap]];
					}
					
				}
			}
		}
	}
	int theac;
	if([[obj valueForKey:@"flatFooted"] boolValue]){
		theac=[[obj valueForKey:@"armourClassFlat"] intValue];
	}else{
		theac=[[obj valueForKey:@"armourClassTotal"] intValue];
	}
	[blurb appendFormat:@". %@ currently has an armour class of %d, a maximum of %d attacks and a speed of %@ feet/round.",[gender capitalizedString],theac,attackCount,[obj valueForKey:@"speedModified"]];
	return blurb;
}
#pragma mark -
#pragma mark Run CurrentAttacks/Spells
#pragma mark

-(BOOL)runCurrentAttacks{
	NSArray *currentAttacks=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"currentAttack" substitutionVariables:[NSDictionary dictionary]]
												 error:nil];
	int i;
	for(i=0;i<[currentAttacks count];i++){
		NSManagedObject *ca=[currentAttacks objectAtIndex:i];
		if(![[ca valueForKey:@"processed"] boolValue]){
			[self getTargetsForCurrentAttack:ca];
			return YES;
		}
	}
	return NO;
}
-(BOOL)runCurrentSpells{
	//NSLog(@"running current spells");
	NSArray *currentSpells=[[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"currentSpell" substitutionVariables:[NSDictionary dictionary]]
												 error:nil] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"spellClass.spell.castingTime==1"]];
	int i;
	for(i=0;i<[currentSpells count];i++){
		NSManagedObject *cs=[currentSpells objectAtIndex:i];
		if(![[cs valueForKey:@"processed"] boolValue]){
			[self runSpellWithCurrentSpell:cs];
			return YES;
		}	
	}
	//NSLog(@"no spells :(");
	return NO;
}
#pragma mark -
#pragma mark Button Methods
#pragma mark
//button methods.
-(IBAction)endRound:(id)sender{
	BOOL hasEnded=NO;
	while(!hasEnded){
		hasEnded=[self endRound];
	}
}
-(BOOL)endRound{
	//run any current attacks/spells that need running.
	if([self runCurrentAttacks]){
		return NO;
	}
	if([self runCurrentSpells]){
		return NO;
	}
	//NSLog(@"no characters left");
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember==1 OR enemyPartyMember==1"]];
	[mainTabs selectTabViewItemAtIndex:2];
	return YES;
}
-(IBAction)fullAttack:(id)sender{
	//first check if using a ranged weapon.
	BOOL moa=NO;
	NSManagedObject *obj=[self currentCharacter];
	if([[obj valueForKey:@"slowed"] boolValue]){
		moa=YES;
	}
	[self runAttackActions:NO
			  forCharacter:obj];
	if([self usingARangedAttackByChar:obj
					   mainAttackOnly:moa]){
		[self setupAttackOOforAction:@"using a ranged weapon"];
	}else{
		//reset display and move to next character.
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		[self setupBattleDisplayWithMessage:nil];
	}
}
-(IBAction)moveAndAttack:(id)sender{
	NSManagedObject *obj=[self currentCharacter];
	[self runAttackActions:YES
			  forCharacter:obj];
	if([self usingARangedAttackByChar:obj
					   mainAttackOnly:NO]){
		[self setupAttackOOforAction:@"moving and using a ranged weapon"];
	}else{
		[self setupAttackOOforAction:@"moving"];
	}
}
-(IBAction)move:(id)sender{
	[self setupAttackOOforAction:@"moving"];
}
-(IBAction)wait:(id)sender{
	//display the wait window.
	NSManagedObject *obj=[self currentCharacter];
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"(mainPartyMember == 1 OR enemyPartyMember == 1) AND initiative <= %@ AND NOT id ==%@",[obj valueForKey:@"initiative"],[obj valueForKey:@"id"]]]];
	//set blurb.
	[waitBlurb setStringValue:[NSString stringWithFormat:@"Please choose which character you want %@ to wait for, otherwise you can choose a custom initiative to wait until, %@ current initiative is %@",[obj valueForKey:@"name"],[AbilityChanged getAdjGenderOfCharacter:obj],[obj valueForKey:@"initiative"]]];
	//Display wait until... window.
	[NSApp beginSheet:waitSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
	[self processWaitButtons];
}
-(IBAction)skipTurn:(id)sender{
	NSManagedObject *obj=[self currentCharacter];
	[obj setValue:[NSNumber numberWithInt:0]
		   forKey:@"attacksLeftThisRound"];
	[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
				   forKey:@"currentCharacter"];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)refocus:(id)sender{
	NSManagedObject *obj=[self currentCharacter];
	[obj setValue:[NSNumber numberWithInt:20+[[obj valueForKey:@"initiativeBonus"] intValue]]
		   forKey:@"initiative"];
	[obj setValue:[NSNumber numberWithInt:0]
		   forKey:@"attacksLeftThisRound"];
	[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
				   forKey:@"currentCharacter"];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)castSpell:(id)sender{
	[spellToCastBlurb setStringValue:[NSString stringWithFormat:@"Please choose a spell for %@ to cast",[[self currentCharacter] valueForKey:@"name"]]];
	NSManagedObject *obj=[self currentCharacter];
	[self setupCharactersSpellsForChar:obj
						  forOverwrite:NO
					   startingAtLevel:INT_MIN];
	[spellsToCastTable reloadData];
	[self processSpellsToCastTable];
	//cast the spell
	[NSApp beginSheet:castSpellSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
}
-(IBAction)turnUndead:(id)sender{
	//turn undead stuff.
	NSManagedObject *obj=[self currentCharacter];
	//check can do it.
	if([[obj valueForKey:@"tuTotal"] intValue]<=[[obj valueForKey:@"tuTimesUsed"] intValue] || ![AbilityChanged characterTurnsOrRebukesUndead:obj]){
		NSBeep();
		[self setupBattleDisplayWithMessage:@"You have no more uses of Turn/Rebuke Undead today."];
		return;
	}
	//roll hd dice.
	int hdRoll=[RandomNumbers randomIntUpTo:20];
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
		NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d for the turn undead max hd dice roll for %@",hdRoll,[obj valueForKey:@"name"]];
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
					   forKey:@"eventLog"];
	}
	hdRoll=hdRoll+[[obj valueForKey:@"tuCtotal"] intValue];
	int clericLevelO=[AbilityChanged levelOfTurningForCharacter:obj];
	int clericLevel;
	if(hdRoll<1){
		clericLevel=clericLevelO-4;
	}else if(hdRoll<4){
		clericLevel=clericLevelO-3;
	}else if(hdRoll<7){
		clericLevel=clericLevelO-2;
	}else if(hdRoll<10){
		clericLevel=clericLevelO-1;
	}else if(hdRoll<13){
		clericLevel=clericLevelO;
	}else if(hdRoll<16){
		clericLevel=clericLevelO+1;
	}else if(hdRoll<19){
		clericLevel=clericLevelO+2;
	}else if(hdRoll<22){
		clericLevel=clericLevelO+3;
	}else if(hdRoll>21){
		clericLevel=clericLevelO+4;
	}
	//check if good that turning, and if evil that it is rebuke.
	if([AbilityChanged isGood:obj]){
		[obj setValue:[NSNumber numberWithBool:YES]
			   forKey:@"turnUndead"];
	}
	if([AbilityChanged isEvil:obj]){
		[obj setValue:[NSNumber numberWithBool:NO]
			   forKey:@"turnUndead"];
	}
	//set max hd affected.
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"type==\"Undead\" AND ((noOfHD <= %d AND noOfHD>0) OR (noOfHD == 0 AND level <= %d)) AND (mainPartyMember == 1 OR enemyPartyMember == 1)",clericLevel,clericLevel]]];
	if([[characterController arrangedObjects] count]==0){
		NSBeep();
		[self setupBattleDisplayWithMessage:@"You cannot actually turn any undead."];
		return;
	}/*else{
		NSLog(@"there are %d evil undead monsters",[[characterController arrangedObjects] count]);
	}*/
	[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"tuTimesUsed"] intValue]+1)]
		   forKey:@"tuTimesUsed"];
	//set blurb
	NSString *turn=@"rebuke";
	if([[obj valueForKey:@"turnUndead"] boolValue]){
		turn=@"turn";
	}
	[turnUndeadBlurb setStringValue:[NSString stringWithFormat:@"Choose which undead characters %@ should %@.",[obj valueForKey:@"name"],turn]];
	//set damage to sheet and display it.
	[turnUndeadTable reloadData];
	//set MaxHD box
	[turnUndeadMaxHD setIntValue:clericLevel];
	//roll total number of HD.
	int dice=[RandomNumbers randomIntUpTo:6]+[RandomNumbers randomIntUpTo:6];
	int bonus=[[obj valueForKey:@"tuHDtotal"] intValue]+clericLevelO;
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
		NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d to find how many hit dice %@ can affect.",dice,bonus,[obj valueForKey:@"name"]];
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
					   forKey:@"eventLog"];
	}
	int damage=dice+bonus;
	[turnUndeadDamageTotal setIntValue:damage];
	[turnUndeadDamageLeft setIntValue:damage];
	[NSApp beginSheet:turnUndeadSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
}
-(IBAction)dischargeSpells:(id)sender{
	[spellDischargeTable reloadData];
	[NSApp beginSheet:spellDischargeSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
}
-(IBAction)changeFeats:(id)sender{
	[featsController setFilterPredicate:[NSPredicate predicateWithFormat:@"ability==0"]];
	//Display change feats sheet.
	NSArray *feats=[featsController arrangedObjects];
	int i;
	for(i=0;i<[feats count];i++){
		NSManagedObject *feat=[feats objectAtIndex:i];
		[feat setValue:[feat valueForKey:@"active"]
				forKey:@"toBeActive"];
	}
	[NSApp beginSheet:changeFeatsSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
	
}
-(IBAction)useSpecialAbility:(id)sender{
		[featsController setFilterPredicate:[NSPredicate predicateWithFormat:@"ability==1 AND active==0 AND (unlimitedUses==1 OR usesLeftPerDay>0)"]];
		[NSApp beginSheet:specialAbilitiesSheet
		   modalForWindow:battleScreen
			modalDelegate:self
		   didEndSelector:nil
			  contextInfo:NULL];
}
-(IBAction)changeWeapon:(id)sender{
	[weaponsTable reloadData];
	[NSApp beginSheet:changeWeaponsSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
}
-(IBAction)editCharacters:(id)sender{
	[self editCharactersCode];
}
-(void)editCharactersCode{
	[battleStore setValue:[NSNumber numberWithBool:YES]
				   forKey:@"continueBattle"];
	[(MenuController *)[NSApp delegate] continueBattleNowOn:YES];
	if(mainTabs==nil || ![battleScreen isVisible]){
		NSLog(@"battle screen not visible cannot edit characters");
		return;
	}
	//[battleController setSelectedObjects:[NSArray arrayWithObject:battleStore]
	if([[mainTabs selectedTabViewItem] isEqualTo:[mainTabs tabViewItemAtIndex:2]]){
		[battleScreen orderOut:self];
		[battleStore setValue:[NSNumber numberWithBool:YES]
					   forKey:@"editingAtEOR"];
	}else{
		[battleScreen orderOut:self];
		[battleStore setValue:[NSNumber numberWithBool:NO]
					   forKey:@"editingAtEOR"];
	}
	[currentlyBusy stopAnimation:self];
	[characterController setFilterPredicate:nil];
	//[spellController setFilterPredicate:nil];
	[weaponController setFilterPredicate:nil];
	//[skillsController setFilterPredicate:nil];
	//[featsController setFilterPredicate:nil];
	[mainScreen makeKeyAndOrderFront:self];
}
-(IBAction)charge:(id)sender{
	NSManagedObject *obj=[self currentCharacter];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]+2]
		   forKey:@"meleeMiscBonus"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassTotal"] intValue]-2]
		   forKey:@"armourClassTotal"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassFlat"] intValue]-2]
		   forKey:@"armourClassFlat"];
	[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassTouch"] intValue]-2]
		   forKey:@"armourClassTouch"];
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"charge"];
	[self runAttackActions:YES
			  forCharacter:obj];
	[self setupAttackOOforAction:@"charging"];
}
-(IBAction)testAttribute:(id)sender{
	[testAttributeTable reloadData];
	[NSApp beginSheet:testAttributeSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];
}
-(NSManagedObject *)currentCharacter{
	NSString *pred=[[characterController filterPredicate] predicateFormat];
	NSArray *sort=[characterController sortDescriptors];
	[characterController setSortDescriptors:[NSArray arrayWithObjects:[[NSSortDescriptor alloc] initWithKey:@"initiative" ascending:NO],[[NSSortDescriptor alloc] initWithKey:@"id" ascending:NO],nil]];
	[characterController rearrangeObjects];
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];
	[characterController rearrangeObjects];
	int cChar=[[battleStore valueForKey:@"currentCharacter"] intValue];
	if([[characterController arrangedObjects] count]<=cChar){
		return nil;
	}
	NSManagedObject *obj=[[characterController arrangedObjects] objectAtIndex:cChar];
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:pred]];
	[characterController setSortDescriptors:sort];
	[characterController rearrangeObjects];
	return obj;
}
#pragma mark -
#pragma mark Random
#pragma mark
-(void)castSpellFromMainScreenWithCharacter:(NSManagedObject *)obj
						   withSSController:(SpellSubviewController *)theSsController{
	//NSLog(@"casting from main screen for character %@",[obj valueForKey:@"name"]);
	ssController=theSsController;
	//new stuff
	mObjC=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
	model=[[mObjC persistentStoreCoordinator] managedObjectModel];
	if([[characterController arrangedObjects] count]==0){
		//NSLog(@"no characters");
		[characterController addObjects:[mainCharacterController arrangedObjects]];
	}
	[characterController setSortDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
	[characterController setSelectedObjects:[NSArray arrayWithObject:obj]];
	[battleStore setValue:[NSNumber numberWithInt:[characterController selectionIndex]]
				   forKey:@"currentCharacter"];
	[spellToCastBlurb setStringValue:[NSString stringWithFormat:@"Please choose a spell for %@ to cast",[obj valueForKey:@"name"]]];
	[self setupCharactersSpellsForChar:obj
						  forOverwrite:NO
					   startingAtLevel:INT_MIN];
	[spellsToCastTable reloadData];
	[self processSpellsToCastTable];
	//cast the spell
	[NSApp beginSheet:castSpellSheet
	   modalForWindow:mainScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL];	
}
-(void)beginningSheetEnded:(NSWindow *)sheet
				returnCode:(int)code
			   contextInfo:(void *)contextInfo{
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)turnUndeadSheetEnded:(id)sender{
	[turnUndeadSheet orderOut:sender];
	[NSApp endSheet:turnUndeadSheet];
	NSString *message=@"";
	//get selected values from the table.
	NSMutableArray *chars=[NSMutableArray arrayWithCapacity:5];
	[chars addObjectsFromArray:[[characterController arrangedObjects] objectsAtIndexes:[turnUndeadTable selectedRowIndexes]]];
	NSMutableIndexSet *is=[[NSMutableIndexSet alloc] init];
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];//reset display.
		[characterController setSelectionIndex:[[battleStore valueForKey:@"currentCharacter"] intValue]];
		NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
		//check whether turning or rebuking
		BOOL notAllDestroyed=NO;
		if([[obj valueForKey:@"turnUndead"] boolValue]){
			//NSLog(@"turning");
			int i;
			for(i=0;i<[chars count];i++){
				NSManagedObject *obj2=[chars objectAtIndex:i];
				if([[obj2 valueForKey:@"noOfHD"] intValue]*2<=[AbilityChanged levelOfTurningForCharacter:obj]){
					//destroyed.
					[is addIndex:i];
					[obj2 setValue:[NSNumber numberWithInt:-10]
							forKey:@"currentHP"];
					if([message isEqualToString:@""]){
						message=[NSString stringWithFormat:@"%@ has been destroyed by %@",[obj2 valueForKey:@"name"],[obj valueForKey:@"name"]];
					}else{
						message=[NSString stringWithFormat:@"%@\n%@ has been destroyed by %@",message,[obj2 valueForKey:@"name"],[obj valueForKey:@"name"]];
					}
				}else{
					[obj2 setValue:[NSNumber numberWithBool:YES]
							forKey:@"turned"];
					notAllDestroyed=YES;
					if([message isEqualToString:@""]){
						message=[NSString stringWithFormat:@"%@ has been turned by %@",[obj2 valueForKey:@"name"],[obj valueForKey:@"name"]];
					}else{
						message=[NSString stringWithFormat:@"%@\n%@ has been turned by %@",message,[obj2 valueForKey:@"name"],[obj valueForKey:@"name"]];
					}
				}
			}
		}else{
			notAllDestroyed=YES;
			//rebuking, so set AC to AC-2, and set active event up for 10 rounds.
			int i;
			NSManagedObject *obj2=[chars objectAtIndex:i];
			[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassDeflection"] intValue]-2)]
					forKey:@"armourClassDeflection"];
			[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassFlat"] intValue]-2)]
					forKey:@"armourClassFlat"];
			[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassTouch"] intValue]-2)]
					forKey:@"armourClassTouch"];
			[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassTotal"] intValue]-2)]
					forKey:@"armourClassTotal"];
			if([message isEqualToString:@""]){
				message=[NSString stringWithFormat:@"%@ has been rebuked by %@",[obj2 valueForKey:@"name"],[obj valueForKey:@"name"]];
			}else{
				message=[NSString stringWithFormat:@"%@\n%@ has been rebuked by %@",message,[obj2 valueForKey:@"name"],[obj valueForKey:@"name"]];
			}
		}
		if(notAllDestroyed){
			NSManagedObject *turnedEvent=[[NSManagedObject alloc] initWithEntity:[NSEntityDescription entityForName:@"ActiveTurning" inManagedObjectContext:mObjC]
												  insertIntoManagedObjectContext:mObjC];
			[turnedEvent setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentRound"] intValue]+10)]
						   forKey:@"lastsUntilRound"];
			[turnedEvent setValue:obj
						   forKey:@"caster"];
			[chars removeObjectsAtIndexes:is];
			[turnedEvent setValue:[NSSet setWithArray:chars]
						   forKey:@"target"];
		}
		[is release];
		//add one to current character.
		[obj setValue:[NSNumber numberWithInt:0]
			   forKey:@"attacksLeftThisRound"];
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		[self setupBattleDisplayWithMessage:message];
}
-(void)alertFromTurningDidEnd:(NSWindow *)panel
				   returnCode:(int)returnCode
				  contextInfo:(void *)contextInfo{
	if(returnCode==NSAlertDefaultReturn){
		//then jump to the next characters go.
		//reduce attacks left to zero.
		NSManagedObject *obj=[self currentCharacter];
		[obj setValue:[NSNumber numberWithInt:0]
			   forKey:@"attacksLeftThisRound"];
		[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
					   forKey:@"currentCharacter"];
		[self setupBattleDisplayWithMessage:nil];
	}else{
		//remove turning effect.
		//NSManagedObjectContext *mObjC=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
		//NSManagedObjectModel *managedObjectModel = [[mObjC persistentStoreCoordinator] managedObjectModel];
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];//reset display.
		[characterController setSelectionIndex:[[battleStore valueForKey:@"currentCharacter"] intValue]];
		NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
		NSArray *array=[[obj valueForKey:@"targetToActiveEvent"] allObjects];
		int i;
		for(i=0;i<[array count];i++){
			NSManagedObject *activeEvent=[array objectAtIndex:i];
			if([[activeEvent entity] isEqualTo:[[model entitiesByName]  objectForKey:@"ActiveTurning"]]){//turn undead event.
				
				NSMutableSet *targets=[activeEvent valueForKey:@"target"];
				[targets removeObject:obj];
				//reverse turning.
				if(!([[activeEvent valueForKey:@"turnUndead"] boolValue])){
					//add two back onto AC.
					[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassDeflection"] intValue]+2)]
						   forKey:@"armourClassDeflection"];
					[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassFlat"] intValue]+2)]
						   forKey:@"armourClassFlat"];
					[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassTouch"] intValue]+2)]
						   forKey:@"armourClassTouch"];
					[obj setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassTotal"] intValue]+2)]
						   forKey:@"armourClassTotal"];
				}
				if([[activeEvent valueForKey:@"target"] count]==0){
					[mObjC deleteObject:activeEvent];
				}
			}
		}
		[obj setValue:[NSNumber numberWithBool:NO]
			   forKey:@"turned"];
		[self setupBattleDisplayWithMessage:nil];
	}
}
-(IBAction)testAttributeInBattle:(id)sender{
	//get skill name.
	int row=[testAttributeTable selectedRow];
	int bonus=[[self tableView:testAttributeTable
	 objectValueForTableColumn:[[testAttributeTable tableColumns] objectAtIndex:1]
						   row:row] intValue];
	NSString *result=[AbilityChanged runTestWithBonus:bonus
												forDC:[difficultyClassInBattle intValue]];
	[testResult setStringValue:result];
} 
-(IBAction)closeTestWindow:(id)sender{
	[testAttributeSheet orderOut:sender];
	[NSApp endSheet:testAttributeSheet];
	[self setupBattleDisplayWithMessage:nil];
}
-(void)processOptionTabsForTabViewItem:(NSTabViewItem *)tabViewItem{
	[castSpellB setKeyEquivalent:@""];
	[castSpellM setKeyEquivalent:@""];
	[skipTurnW setKeyEquivalent:@""];
	[skipTurnS setKeyEquivalent:@""];
	[waitS setKeyEquivalent:@""];
	[waitW setKeyEquivalent:@""];
	[attackS setKeyEquivalent:@""];
	NSRect rect=[battleScreen frame];
	if([tabViewItem isEqualTo:[[optionTabs tabViewItems] objectAtIndex:0]]){
		[castSpellB setKeyEquivalent:@"s"];
		rect.origin.y=rect.origin.y+(rect.size.height-432);
		rect.size.height=432;
	}
	if([tabViewItem isEqualTo:[[optionTabs tabViewItems] objectAtIndex:2]]){
		[castSpellM setKeyEquivalent:@"s"];
		rect.origin.y=rect.origin.y+(rect.size.height-432);
		rect.size.height=432;
	}
	if([tabViewItem isEqualTo:[[optionTabs tabViewItems] objectAtIndex:3]]){
		rect.origin.y=rect.origin.y+(rect.size.height-432);
		rect.size.height=432;
	}else if([tabViewItem isEqualTo:[[optionTabs tabViewItems] objectAtIndex:1]]){
		[skipTurnW setKeyEquivalent:@"s"];
		[waitW setKeyEquivalent:@"w"];
		rect.origin.y=rect.origin.y+(rect.size.height-403);
		rect.size.height=403;
	}else if([tabViewItem isEqualTo:[[optionTabs tabViewItems] objectAtIndex:4]]){
		rect.origin.y=rect.origin.y+(rect.size.height-654);
		rect.size.height=654;
	}else if([tabViewItem isEqualTo:[[optionTabs tabViewItems] objectAtIndex:5]]){
		[waitS setKeyEquivalent:@"w"];
		[skipTurnS setKeyEquivalent:@"s"];
		[attackS setKeyEquivalent:@"a"];
		rect.origin.y=rect.origin.y+(rect.size.height-461);
		rect.size.height=461;
	}
	[battleScreen setFrame:rect display:YES];
	NSManagedObject *obj=[self currentCharacter];
	if([[obj valueForKey:@"slowed"] boolValue]){
		[moveAndAttackB setKeyEquivalent:@""];
		[moveAndAttackB setEnabled:NO];
		[moveAndAttackE setEnabled:NO];
		[fullAttackB setTitle:@"Attack"];
		[attackS setKeyEquivalent:@""];
		[fullAttackB setKeyEquivalent:@"a"];
		[fullAttackE setTitle:@"Attack"];
	}else{
		[attackS setKeyEquivalent:@""];
		[moveAndAttackB setKeyEquivalent:@"a"];
		[moveAndAttackB setEnabled:YES];
		[moveAndAttackE setEnabled:YES];
		[fullAttackB setTitle:@"Full Attack"];
		[fullAttackB setKeyEquivalent:@"f"];
		[fullAttackE setTitle:@"Full Attack"];
	}
	if([[obj valueForKey:@"spellClass"] count]==0){
		[castSpellB setEnabled:NO];
		[castSpellM setEnabled:NO];
		[castSpellE setEnabled:NO];
	}else{
		[castSpellB setEnabled:YES];
		[castSpellM setEnabled:YES];
		[castSpellE setEnabled:YES];
	}
	if([[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"ability==1"]] count]==0){
		[specialAbilityB setEnabled:NO];
		[specialAbilityA setEnabled:NO];
		[specialAbilityE setEnabled:NO];
	}else{
		[specialAbilityB setEnabled:YES];
		[specialAbilityA setEnabled:YES];
		[specialAbilityE setEnabled:YES];		
	}
	if([[obj valueForKey:@"usesWeapons"] boolValue]){
		[changeWeaponA setEnabled:YES];
		[changeWeaponE setEnabled:YES];
	}else{
		[changeWeaponA setEnabled:NO];
		[changeWeaponE setEnabled:NO];
	}
	if([[obj valueForKey:@"turnUndead"] boolValue]){
		[turnUndeadM setTitle:@"Turn Undead"];
		[turnUndeadE setTitle:@"Turn Undead"];
	}else{
		[turnUndeadM setTitle:@"Rebuke Undead"];
		[turnUndeadE setTitle:@"Rebuke Undead"];
	}
	//turn undead checking.
	if([AbilityChanged characterTurnsOrRebukesUndead:obj]){
		[turnUndeadM setEnabled:YES];
		[turnUndeadE setEnabled:YES];
	}else{
		[turnUndeadM setEnabled:NO];
		[turnUndeadE setEnabled:NO];
	}
	//check spell discharge.
	NSArray *array=[[obj valueForKey:@"casterOfActiveEvent"] allObjects];
	int i;
	int count=0;
	for(i=0;i<[array count];i++){
		NSManagedObject *event=[array objectAtIndex:i];
		if(![[event entity] isEqualTo:[[model entitiesByName]  objectForKey:@"ActiveSpell"]]){
			continue;
		}
		if([[[event valueForKey:@"spell"] valueForKey:@"durDischarge"] boolValue]){
			count++;
		}
	}
	if(count==0){
		[spellDischargeM setEnabled:NO];
		[spellDischargeE setEnabled:NO];
	}else{
		[spellDischargeM setEnabled:YES];
		[spellDischargeE setEnabled:YES];
	}
}
#pragma mark -
#pragma mark Wait methods
#pragma mark 
-(IBAction)waitUntilBefore:(id)sender{
	[waitSheet orderOut:self];
	[NSApp endSheet:waitSheet];
	NSManagedObject *obj2;
	obj2=[[characterController selectedObjects] objectAtIndex:0];
	int theInit=[[obj2 valueForKey:@"initiative"] intValue]+1;
	NSManagedObject *obj=[self currentCharacter];
	if(theInit<[[obj valueForKey:@"initiative"] intValue]){//so doesn't change if higher, then could display an error message.
		[obj setValue:[NSNumber numberWithInt:theInit]
			   forKey:@"initiative"];
	}
	[characterController rearrangeObjects];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)waitUntil:(id)sender{
	[waitSheet orderOut:self];
	[NSApp endSheet:waitSheet];
	NSManagedObject *obj2=[[characterController selectedObjects] objectAtIndex:0];
	int theInit=[[obj2 valueForKey:@"initiative"] intValue];
	NSManagedObject *obj=[self currentCharacter];
	[obj setValue:[NSNumber numberWithInt:theInit]
		   forKey:@"initiative"];
	[characterController rearrangeObjects];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)waitUntilAfter:(id)sender{
	[waitSheet orderOut:self];
	[NSApp endSheet:waitSheet];
	NSManagedObject *obj2=[[characterController selectedObjects] objectAtIndex:0];
	int theInit=[[obj2 valueForKey:@"initiative"] intValue]-1;
	NSManagedObject *obj=[self currentCharacter];
	[obj setValue:[NSNumber numberWithInt:theInit]
		   forKey:@"initiative"];
	[characterController rearrangeObjects];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)waitUntilCustomInitiative:(id)sender{
	[waitSheet orderOut:self];
	[NSApp endSheet:waitSheet];
	int theInit=[customInitToWaitFor intValue];
	NSManagedObject *obj=[self currentCharacter];
	if(theInit<[[obj valueForKey:@"initiative"] intValue]){
		[obj setValue:[NSNumber numberWithInt:theInit]
			   forKey:@"initiative"];
		[characterController rearrangeObjects];
		[self setupBattleDisplayWithMessage:nil];
	}else{
		NSBeep();
		[self setupBattleDisplayWithMessage:@"You cannot wait until an initiative that is greater or equal to your current initiative."];
	}
}
-(IBAction)cancelWaitWindow:(id)sender{
	[waitSheet orderOut:self];
	[NSApp endSheet:waitSheet];
}
-(void)processWaitButtons{
	int row=[waitTable selectedRow];
	if(row==-1){
		return;
	}
	NSArray *array=[characterController arrangedObjects];
	if(![[waitTable window] isVisible]){
		//NSLog(@"waitTable isn't actually visible");
		return;
	}
	if(row>=[array count]){
		NSLog(@"row given for wait table beyond the bounds of character list.");
		return;
	}
	[waitTable setDelegate:nil];
	NSManagedObject *obj=[self currentCharacter];
	NSManagedObject *selObj=[array objectAtIndex:row];
	if([[obj valueForKey:@"initiative"] intValue]==[[selObj valueForKey:@"initiative"] intValue]){
		[waitUntilSameButton setEnabled:NO];
		[waitUntilBeforeButton setEnabled:NO];
	}else if([[obj valueForKey:@"initiative"] intValue]==[[selObj valueForKey:@"initiative"] intValue]+1){
		[waitUntilSameButton setEnabled:YES];
		[waitUntilBeforeButton setEnabled:NO];
	}else{
		[waitUntilSameButton setEnabled:YES];
		[waitUntilBeforeButton setEnabled:YES];
	}
	[waitTable selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
		   byExtendingSelection:NO];
	[waitTable setDelegate:self];
}
#pragma mark -
#pragma mark More random
#pragma mark 
-(IBAction)xModifierChanged:(id)sender{
	if([[featsController selectedObjects] count]==0){
		NSLog(@"no feat selected, xMod change code cannot run.");
		return;
	}
	NSManagedObject *feat=[[featsController selectedObjects] objectAtIndex:0];
	if([[feat valueForKey:@"active"] boolValue] && [FeatActions inCombatFeatShouldActivate:feat]){
		[FeatActions activateInCodeTheFeat:feat
							 nowShouldBeOn:NO];
		[feat setValue:[NSNumber numberWithInt:[xModTF intValue]]
				forKey:@"xValue"];
		[FeatActions activateInCodeTheFeat:feat
							 nowShouldBeOn:YES];
	}else{
		[feat setValue:[NSNumber numberWithInt:[xModTF intValue]]
				forKey:@"xValue"];
	}
}
-(IBAction)changeFeatSheetEnded:(id)sender{
	[changeFeatsSheet orderOut:sender];
	[NSApp endSheet:changeFeatsSheet];
	[featsController setFilterPredicate:[NSPredicate predicateWithFormat:@"active==1 AND toBeActive==0"]];
	NSArray *featsToGo=[featsController arrangedObjects];
	int i;
	for(i=0;i<[featsToGo count];i++){
		NSManagedObject *feat=[featsToGo objectAtIndex:i];
		if([FeatActions inCombatFeatShouldActivate:feat]){
			[FeatActions activateInCodeTheFeat:feat
								 nowShouldBeOn:NO];
		}else{
			[feat setValue:[NSNumber numberWithBool:NO]
					forKey:@"active"];
		}
	}
	[featsController setFilterPredicate:[NSPredicate predicateWithFormat:@"active==0 AND toBeActive==1"]];
	featsToGo=[featsController arrangedObjects];
	for(i=0;i<[featsToGo count];i++){
		NSManagedObject *feat=[featsToGo objectAtIndex:i];
		if([FeatActions inCombatFeatShouldActivate:feat]){
			[FeatActions activateInCodeTheFeat:feat
								 nowShouldBeOn:YES];
		}else{
			[feat setValue:[NSNumber numberWithBool:YES]
					forKey:@"active"];
		}
	}
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)specialAbilitySheetEnded:(id)sender{
	[specialAbilitiesSheet orderOut:sender];
	[NSApp endSheet:specialAbilitiesSheet];
	NSManagedObject *abil=[[featsController selectedObjects] objectAtIndex:0];
	NSManagedObject *obj=[self currentCharacter];
	//takes off a daily use as needed.
	if(![[abil valueForKey:@"unlimitedUses"] boolValue]){
		[abil setValue:[NSNumber numberWithInt:[[abil valueForKey:@"timesUsedPerDay"] intValue]+1]
				forKey:@"timesUsedPerDay"];
		[abil setValue:[NSNumber numberWithInt:[[abil valueForKey:@"usesLeftPerDay"] intValue]-1]
				forKey:@"usesLeftPerDay"];
	}
	//casts as a spell as required.
	if([[abil valueForKey:@"type"] intValue]==3){
		int casterLevel;
		if([[abil valueForKey:@"castAtCurrentLevel"] boolValue]){
			if([[obj valueForKey:@"noOfHD"] intValue]==0){
				casterLevel=[[obj valueForKey:@"level"] intValue];
			}else{
				casterLevel=[[obj valueForKey:@"noOfHD"] intValue];
			}
		}else{
			casterLevel=[[abil valueForKey:@"castAtLevel"] intValue];
		}
		//cast a spell.
		NSManagedObject *cs=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentSpell"]
									 insertIntoManagedObjectContext:mObjC];
		[cs setValue:[abil valueForKey:@"spell"]
			  forKey:@"spell"];
		[cs setValue:obj
			  forKey:@"caster"];
		[cs setValue:[NSNumber numberWithInt:casterLevel]
			  forKey:@"casterLevel"];
		[cs setValue:[NSNumber numberWithInt:[SpellMethods averageSpellLevelForSpell:[abil valueForKey:@"spell"]]]
			  forKey:@"spellLevel"];
		[self runSpellWithCurrentSpell:cs];
	}else{
		if([FeatActions inCombatFeatShouldActivate:abil]){
			[FeatActions activateInCodeTheFeat:abil
								 nowShouldBeOn:YES];
			if(![[abil valueForKey:@"lastsForever"] boolValue]){
				//NSLog(@"ability doesn't last forever");
				NSManagedObject *ae=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"ActiveFeat"]
											 insertIntoManagedObjectContext:mObjC];
				[ae setValue:abil
					  forKey:@"feat"];
				[ae setValue:obj
					  forKey:@"caster"];
				if([[abil valueForKey:@"runsUntilBattleEnded"] boolValue]){
					[ae setValue:[NSNumber numberWithInt:0]
						  forKey:@"lastsUntilRound"];
				}else{
					[ae setValue:[NSNumber numberWithInt:[[battleStore valueForKey:@"currentRound"] intValue]+[[abil valueForKey:@"timeLastsFor"] intValue]]
						  forKey:@"lastsUntilRound"];
					//NSLog(@"ability dies in round: %@",[ae valueForKey:@"lastsUntilRound"]);
				}
			}	
		}
	}
	[self setupBattleDisplayWithMessage:nil];
}
-(void)displayFeatTargetSheetByChar:(NSManagedObject *)obj
							forFeat:(NSManagedObject *)feat{
	//NSLog(@"displaying feat target sheet");
	[featTargetBlurb setStringValue:[NSString stringWithFormat:@"Please choose the targets for %@'s feat %@",[obj valueForKey:@"name"],[feat valueForKey:@"name"]]];
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id != %@ AND (enemyPartyMember==1 OR mainPartyMember==1)",[obj valueForKey:@"id"]]]];
	if([feat valueForKey:@"target"]!=nil){
		[characterController setSelectedObjects:[[feat valueForKey:@"target"] allObjects]];
	}
	[featTargetTable reloadData];
	[NSApp beginSheet:featTargetSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:@selector(featTargetSheetEnded:returnCode:feat:)
		  contextInfo:feat];
	//NSLog(@"targetting feats");
}
-(IBAction)refreshFeatTargetsTable:(id)sender{
	NSManagedObject *obj=[self currentCharacter];
	NSMutableString *thePredicate=[NSMutableString stringWithCapacity:15];
	NSUserDefaults *userDef=[NSUserDefaults standardUserDefaults];
	if([[obj valueForKey:@"mainPartyMember"] boolValue] && [[obj valueForKey:@"enemyPartyMember"] boolValue]){
		if([userDef boolForKey:@"showFriends"] || [userDef boolForKey:@"showEnemies"]){
			[thePredicate appendString:@"mainPartyMember==1 OR enemyPartyMember==1"];
		}
	}else{
		if(([[obj valueForKey:@"mainPartyMember"] boolValue] && [userDef boolForKey:@"showFriends"]) || ([[obj valueForKey:@"enemyPartyMember"] boolValue] && [userDef boolForKey:@"showEnemies"])){
				[thePredicate appendString:@"mainPartyMember==1"];
		}
		if(([[obj valueForKey:@"mainPartyMember"] boolValue] && [userDef boolForKey:@"showEnemies"]) || ([[obj valueForKey:@"enemyPartyMember"] boolValue] && [userDef boolForKey:@"showFriends"])){
			if([thePredicate isEqualToString:@""]){
				[thePredicate appendString:@"enemyPartyMember==1"];;
			}else{
				[thePredicate appendString:@" OR enemyPartyMember==1"];
			}
		}
	}
	if(![userDef boolForKey:@"showInactive"]){
		if([thePredicate isEqualToString:@""]){
			[thePredicate appendString:@"paralysed==0 AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")"];
		}else{
			[thePredicate appendString:@" AND paralysed==0 AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")"];
		}
	}
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:thePredicate]];
	[featTargetTable reloadData];
}
-(IBAction)featTargetSheetCancelled:(id)sender{
	[featTargetSheet orderOut:sender];
	[NSApp endSheet:featTargetSheet returnCode:-1];
}
-(IBAction)featTargetSheetEnded:(id)sender{
	[featTargetSheet orderOut:sender];
	[NSApp endSheet:featTargetSheet returnCode:0];
}
-(void)featTargetSheetEnded:(NSWindow *)sheet
				 returnCode:(int)returnCode
					   feat:(NSManagedObject *)feat{
	if([[feat valueForKey:@"featAffects"] intValue]==1 && [FeatActions inCombatFeatShouldActivate:feat]){
		[FeatActions activateInCodeTheFeat:feat
							 nowShouldBeOn:NO];
	}
	if(returnCode==-1){
		[feat setValue:nil
				forKey:@"target"];
	}else if(returnCode==1){
		return;
	}else if(returnCode==2){
		NSArray *array=[[NSArray alloc] initWithObjects:featTargetSheet,feat,nil];
		if([mainScreen isVisible]){
			[NSApp beginSheet:infoPanel
			   modalForWindow:mainScreen
				modalDelegate:self
			   didEndSelector:@selector(playerInfoClosed:returnCode:contextInfo:)
				  contextInfo:array];
		}else{
			[NSApp beginSheet:infoPanel
			   modalForWindow:battleScreen
				modalDelegate:self
			   didEndSelector:@selector(playerInfoClosed:returnCode:contextInfo:)
				  contextInfo:array];
		}
		return;
	}else{
		[feat setValue:[NSSet setWithArray:[[characterController arrangedObjects] objectsAtIndexes:[featTargetTable selectedRowIndexes]]]
				forKey:@"target"];
		if([[feat valueForKey:@"featAffects"] intValue]==1 && [FeatActions inCombatFeatShouldActivate:feat]){
			[FeatActions activateInCodeTheFeat:feat
								 nowShouldBeOn:YES];
		}
	}
	[self setupBattleDisplayWithMessage:nil];
}

-(IBAction)changeWeaponSheetEnded:(id)sender{
	[changeWeaponsSheet orderOut:sender];
	[NSApp endSheet:changeWeaponsSheet];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)setDefaultWeapon:(id)sender{
	if([[characterController selectedObjects] count]==0 || [[weaponController selectedObjects] count]==0)
		return;
	NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
	NSManagedObject *newWeap=[[weaponController selectedObjects] objectAtIndex:0];
	[AbilityChanged setDefaultWeaponForChar:obj
								 withWeapon:newWeap];
	[weaponsTable reloadData];
}
-(IBAction)setOffHandWeapon:(id)sender{
	if([[characterController selectedObjects] count]==0 || [[weaponController selectedObjects] count]==0)
		return;
	NSManagedObject *newWeap=[[weaponController selectedObjects] objectAtIndex:0];
	NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
	[AbilityChanged setOffHandWeaponForChar:obj
								 withWeapon:newWeap];
	[weaponsTable reloadData];
}
-(IBAction)cancelOffHandWeapon:(id)sender{
	if([[characterController selectedObjects] count]==0)
		return;
	NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
	[AbilityChanged cancelOffHandWeaponForChar:obj];
	[weaponsTable reloadData];
}
#pragma mark -
#pragma mark Spells
#pragma mark
-(NSString *)checkTheActiveSpell:(NSManagedObject *)activeEvent{
	//if you want processing from this method return a blank string i.e. @"".
	NSManagedObject *obj=[activeEvent valueForKey:@"caster"];
	NSManagedObject *spell=[activeEvent valueForKey:@"spell"];
	//check active event not about to be killed.
	if([[activeEvent valueForKey:@"lastsUntilRound"] intValue]<=[[battleStore valueForKey:@"currentRound"] intValue] && [[activeEvent valueForKey:@"lastsUntilRound"] intValue]!=0){
		return @"";
	}
	//check if the spell is a summoning spell as in that case we also just want to return.
	if([[spell valueForKey:@"type"] intValue]==3){
		return @"";
	}
	NSManagedObject *currentSpell=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentSpell"]
										   insertIntoManagedObjectContext:mObjC];
	[currentSpell setValue:obj
					forKey:@"caster"];
	//this is OK as you don't actually care what level the spell is for its further usage. (It's just a wrapper here).
	[currentSpell setValue:[[spell valueForKey:@"spellClass"] anyObject]
					forKey:@"spellClass"];
	[currentSpell setValue:[activeEvent valueForKey:@"abilityBonus"]
					forKey:@"abilityBonus"];
	[currentSpell setValue:[activeEvent valueForKey:@"casterLevel"]
					forKey:@"casterLevel"];
	[currentSpell setValue:[activeEvent valueForKey:@"spellLevel"]
					forKey:@"spellLevel"];
	[currentSpell setValue:[activeEvent valueForKey:@"feat"]
					forKey:@"feat"];
	[currentSpell setValue:[NSNumber numberWithBool:NO]
					forKey:@"originalCasting"];
	//check if new targets.
	if([[spell valueForKey:@"targetChangesEachRound"] boolValue]){
		//NSLog(@"new targets");
		if([[obj valueForKey:@"paralysed"] boolValue]){
			//target sheet says char slowed/incapacitated.
			[spellTargetBlurb setStringValue:[NSString stringWithFormat:@"%@ has successfully cast the spell %@ please choose who it is targetting. Please note this character is incapacitated and has no control over this spell.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
		}else{
			//target sheet says char normal.
			[spellTargetBlurb setStringValue:[NSString stringWithFormat:@"%@ has successfully cast the spell %@ please choose who it is targetting.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
		}
		//NSLog(@"about to start sheet");
		//set up duration label.
		NSString *durLabel;
		if([[spell valueForKey:@"durMeasuredIn"] intValue]==0){
			durLabel=@"rounds";
		}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==1){
			durLabel=@"minutes";
		}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==2){
			durLabel=@"hours";
		}else{
			durLabel=@"days";
		}
		[self displaySpellTargetSheetForCurrentSpell:currentSpell
										 forDuration:[[activeEvent valueForKey:@"lastsUntilRound"] intValue]-[[battleStore valueForKey:@"currentRound"] intValue]
									forDurationLabel:@"rounds"
											forRange:[activeEvent valueForKey:@"range"]
									   forRangeLabel:[activeEvent valueForKey:@"rangeLabel"]
									  forCustomBlurb:YES];
		//NSLog(@"sheet 'displayed'");
		return nil;
	}else{
		//else process damage.
		int j;
		NSArray *targets;
		targets=[[activeEvent valueForKey:@"target"] allObjects];
		NSString *message=[NSString stringWithFormat:@"%@'s spell %@ is still active.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]];
		for(j=0;j<[targets count];j++){
			NSManagedObject *st=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"SpellTarget"]
										 insertIntoManagedObjectContext:mObjC];
			[st setValue:[targets objectAtIndex:j]
				  forKey:@"character"];
			[st setValue:[[targets objectAtIndex:j] valueForKey:@"name"]
				  forKey:@"name"];
			NSMutableSet *set=[NSMutableSet setWithCapacity:3];
			[set setSet:[currentSpell valueForKey:@"spellTarget"]];
			[set addObject:st];
			[currentSpell setValue:set
							forKey:@"spellTarget"];
			NSString *message2=[self processEffectFromCurrentSpell:currentSpell
													 onSpellTarget:st];
			if([message isEqualToString:@""]){
				message=message2;								
			}else{
				message=[NSString stringWithFormat:@"%@\n%@",message,message2];
			}
		}
		//so message is displayed and currentSpell thrown away as required.
		[currentSpell setValue:[NSNumber numberWithBool:YES]
						forKey:@"processed"];
		[currentSpell setValue:message
						forKey:@"resultMessage"];
		//NSLog(@"currentSpell=%@",currentSpell);
		//return message;
		return @"";
	}
}
-(void)setupCharactersSpellsForChar:(NSManagedObject *)obj
					   forOverwrite:(BOOL)overwrite
					startingAtLevel:(int)startLevel{
	//NSLog(@"starting processing of char spells setup");
	if(charactersSpellClasses==nil){
		charactersSpellClasses=[[NSMutableArray alloc] initWithCapacity:5];
	}
	int i;
	for(i=0;i<3;i++){
		//NSLog(@"character=%@",[obj valueForKey:@"name"]);
		NSManagedObject *characterClass=[obj valueForKey:[NSString stringWithFormat:@"characterClass%d",i+1]];
		if([[characterClass valueForKey:@"castsSpells"] boolValue]){
			NSArray *spellLevels=[[[[obj valueForKey:@"spellLevel"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"characterClass.name like[c] \"%@\" AND level>=%d",[characterClass valueForKey:@"name"],startLevel]]] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"level" ascending:YES]]];
			if([[characterClass valueForKey:@"allSpontaneous"] boolValue]){
				NSSet *spellClasses1=[characterClass valueForKey:@"spellClass"];
				NSMutableSet *spellClasses2=[NSMutableSet setWithCapacity:10];
				[spellClasses2 setSet:[obj valueForKey:@"spellClass"]];
				[spellClasses2 intersectSet:spellClasses1];
				NSArray *sc2=[[spellClasses2 allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"level>=%d",startLevel]]];
				int j;
				NSMutableArray *sct=[NSMutableArray arrayWithCapacity:[sc2 count]];
				for(j=0;j<[sc2 count];j++){
					NSManagedObject *spellClass=[sc2 objectAtIndex:j];
					NSManagedObject *tempSpellClass=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"TempSpellClass"] insertIntoManagedObjectContext:mObjC];
					[tempSpellClass setValue:spellClass
									  forKey:@"spellClass"];
					[tempSpellClass setValue:obj
									  forKey:@"character"];
					int slEntry=[[spellClass valueForKey:@"level"] intValue]-[[characterClass valueForKey:@"minimumSpellLevel"] intValue];
					int spellsLeft=[[[spellLevels objectAtIndex:slEntry] valueForKey:@"spellsLeft"] intValue];
					[tempSpellClass setValue:[NSNumber numberWithInt:spellsLeft]
								  forKey:@"noOfSpellsLeftTemp"];
					[tempSpellClass setValue:nil
								  forKey:@"castAtLevelTemp"];
					[sct addObject:tempSpellClass];
				}
				[charactersSpellClasses setArray:sct];
				[charactersSpellClasses sortUsingDescriptors:[NSArray arrayWithObjects:[[NSSortDescriptor alloc] initWithKey:@"spellClass.level" ascending:YES],[[NSSortDescriptor alloc] initWithKey:@"spellClass.spell.name" ascending:YES],nil]];
			}else{
				NSMutableSet *spellClasses2=[NSMutableSet setWithCapacity:1];
				//set up set of all the characters spells.
				if([[characterClass valueForKey:@"healOrHarmSpontaneous"] boolValue] || [[characterClass valueForKey:@"summoningSpontaneous"] boolValue]){
					NSSet *spellClasses1=[characterClass valueForKey:@"spellClass"];
					[spellClasses2 setSet:[obj valueForKey:@"spellClass"]];
					[spellClasses2 intersectSet:spellClasses1];
				}
				int j;
				for(j=0;j<[spellLevels count];j++){
					NSManagedObject *spellLevel=[spellLevels objectAtIndex:j];
					//now process.
					NSArray *arrayOfMemSpells=[[[[spellLevel valueForKey:@"memorisedSpell"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"castable == 1"]] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
					NSMutableArray *spontSCs=[NSMutableArray arrayWithCapacity:1];
					if(!overwrite){
						//check if there are spells to overwrite.
						int g;
						BOOL noSLsGreater=YES;
						for(g=j;g<[spellLevels count];g++){
							NSManagedObject *superLevel=[spellLevels objectAtIndex:g];
							if([[superLevel valueForKey:@"spellsLeft"] intValue]>0 && [[[[superLevel valueForKey:@"memorisedSpell"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"castable==1"]] count]>0){
								NSLog(@"a spell left");
								noSLsGreater=NO;
								break;
							}
						}
						//no possible spells to overwrite.
						if(noSLsGreater){
							continue;
						}
						//if we are overwriting spontaneous spells are useless and don't want adding to the list.
						if([[characterClass valueForKey:@"healOrHarmSpontaneous"] boolValue]){
							if([[obj valueForKey:@"turnUndead"] boolValue] || [AbilityChanged isGood:obj]){
								[spontSCs addObjectsFromArray:[[spellClasses2 allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"spell.type==0 AND level==%d",j]]]];
							}else{
								[spontSCs addObjectsFromArray:[[spellClasses2 allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"spell.type==1 AND level==%d",j]]]];
							}
						} 
						if([[characterClass valueForKey:@"summoningSpontaneous"] boolValue]){
							[spontSCs addObjectsFromArray:[[spellClasses2 allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"spell.type==3 AND level==%d",j]]]];
						}
						int k;
						for(k=0;k<[spontSCs count];k++){
							NSManagedObject *spontSpellClass=[spontSCs objectAtIndex:k];
							int noLeft=[[spellLevel valueForKey:@"spellsLeft"] intValue];
							if(![[spellLevel valueForKey:@"castDomainSpellToday"] boolValue] && [[characterClass valueForKey:@"castsDomainSpells"] boolValue]){
								noLeft++;
							}
							NSManagedObject *tempSpellClass=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"TempSpellClass"] insertIntoManagedObjectContext:mObjC];
							[tempSpellClass setValue:obj
											  forKey:@"character"];
							[tempSpellClass setValue:spontSpellClass
											  forKey:@"spellClass"];
							[tempSpellClass setValue:[NSNumber numberWithInt:noLeft]
											  forKey:@"noOfSpellsLeftTemp"];
							[tempSpellClass setValue:nil
											  forKey:@"castAtLevelTemp"];
							[charactersSpellClasses addObject:tempSpellClass];
						}
					}
					if([arrayOfMemSpells count]==0 || [[spellLevel valueForKey:@"spellsLeft"] intValue]==0){
						//no spells available at this level.
						//NSLog(@"no spells left");
						continue;
					}
					//now process all the other spells.
					NSMutableArray *memSpells=[NSMutableArray arrayWithCapacity:3];
					int k;
					for(k=0;k<[arrayOfMemSpells count];k++){
						NSManagedObject *memSpell=[arrayOfMemSpells objectAtIndex:k];
						NSManagedObject *spellClass=[memSpell valueForKey:@"spellClass"];
						if(spellClass==nil){
							NSLog(@"Error spellClass for Memorised Spell '%@' is nil",[memSpell valueForKey:@"name"]);
							continue;
						}
						if(![spontSCs containsObject:spellClass]){
							//spell not a "spontaneous" spell which is already in the list.
							//check if spell already in the list of memorised spells.
							int l;
							NSManagedObject *tempSpellClass=nil;
							for(l=0;l<[memSpells count];l++){
								if([[[memSpells objectAtIndex:l] valueForKey:@"spellClass"] isEqualTo:spellClass]){
									tempSpellClass=[memSpells objectAtIndex:l];
									break;
								}
							}
							if(tempSpellClass!=nil){
								[tempSpellClass setValue:[NSNumber numberWithInt:[[tempSpellClass valueForKey:@"noOfSpellsLeftTemp"] intValue]+1]
											  forKey:@"noOfSpellsLeftTemp"];
							}else{
								tempSpellClass=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"TempSpellClass"] insertIntoManagedObjectContext:mObjC];
								[tempSpellClass setValue:obj
												  forKey:@"character"];
								[tempSpellClass setValue:spellClass
												  forKey:@"spellClass"];
								[tempSpellClass setValue:[NSNumber numberWithInt:1]
											  forKey:@"noOfSpellsLeftTemp"];
								[tempSpellClass setValue:[memSpell valueForKey:@"feat"]
											  forKey:@"featsTemp"];
								if([[spellClass valueForKey:@"level"] intValue]!=[[spellLevel valueForKey:@"level"] intValue]){
									[tempSpellClass setValue:[spellLevel valueForKey:@"level"]
												  forKey:@"castAtLevelTemp"];
								}else{
									[tempSpellClass setValue:nil
													  forKey:@"castAtLevelTemp"];
								}
								[memSpells addObject:tempSpellClass];
								[charactersSpellClasses addObject:tempSpellClass];
							}
						}
					}
				}
			}
		}
		if(i==0){
			c1=[charactersSpellClasses count];
			//NSLog(@"c1=%d",c1);
		}else if(i==1){
			c2=[charactersSpellClasses count];
			//NSLog(@"c2=%d",c2);
		}
	}
	[charactersSpellClasses sortUsingDescriptors:[NSArray arrayWithObjects:[[NSSortDescriptor alloc] initWithKey:@"spellClass.level" ascending:YES], [[NSSortDescriptor alloc] initWithKey:@"spellClass.spell.name" ascending:YES], [[NSSortDescriptor alloc] initWithKey:@"spellClass.domainSpell" ascending:YES], nil]];
}
-(IBAction)editMetamagicFeats:(id)sender{
	[castSpellSheet orderOut:sender];
	[NSApp endSheet:castSpellSheet];
	NSManagedObject *tempSpellClass=[charactersSpellClasses objectAtIndex:[spellsToCastTable selectedRow]];
	NSManagedObject *newTempSpellClass=[tempSpellClass duplicate:tempSpellClass];
	NSWindow *displayScreen;
	if([mainScreen isVisible]){
		displayScreen=mainScreen;
	}else{
		displayScreen=battleScreen;
	}
	if(mmFeatController==nil){
		mmFeatController=[[MetaMagicFeatController alloc] init];
	}
	//NSLog(@"ctv window=%@",[characterTabView window]);
	[mmFeatController displayMetamagicFeatScreenForTempSpellClass:newTempSpellClass
													modalDelegate:self
													  endSelector:@selector(metamagicSheetDidEnd:returnCode:contextInfo:)
												   modalForWindow:displayScreen];	
}
-(IBAction)cancelSpellChosen:(id)sender{
	[castSpellSheet orderOut:sender];
	[NSApp endSheet:castSpellSheet];
	int i;
	for(i=0;i<[charactersSpellClasses count];i++){
		[mObjC deleteObject:[charactersSpellClasses objectAtIndex:i]];
	}
	[charactersSpellClasses removeAllObjects];
	[self setupBattleDisplayWithMessage:nil];
}
-(void)metamagicSheetDidEnd:(NSWindow *)panel
				 returnCode:(int)returnCode
				contextInfo:(NSManagedObject *)tempSpellClass{
	if(returnCode==1){
		[mObjC deleteObject:tempSpellClass];
	}else{
		NSManagedObject *oldTempSpellClass=[charactersSpellClasses objectAtIndex:[spellsToCastTable selectedRow]];
		[charactersSpellClasses replaceObjectAtIndex:[spellsToCastTable selectedRow] withObject:tempSpellClass];
		[mObjC deleteObject:oldTempSpellClass];
	}
	if([mainScreen isVisible]){
		[NSApp beginSheet:castSpellSheet
		   modalForWindow:mainScreen
			modalDelegate:self
		   didEndSelector:nil
			  contextInfo:NULL];
	}else{
		[NSApp beginSheet:castSpellSheet
		   modalForWindow:battleScreen
			modalDelegate:self
		   didEndSelector:nil
			  contextInfo:NULL];
	}
}
-(IBAction)spellChosen:(id)sender{
	[castSpellSheet orderOut:sender];
	[NSApp endSheet:castSpellSheet returnCode:0];
	//NSLog(@"now casting");
	//
	//NOW CASTING..
	//
	//ms means not casting from battle.
	int row=[spellsToCastTable selectedRow];
	NSManagedObject *tempSpellClass=[charactersSpellClasses objectAtIndex:row];
	NSManagedObject *obj=[tempSpellClass valueForKey:@"character"];
	BOOL ms=[mainScreen isVisible];
	if(!ms){
		[obj setValue:[NSNumber numberWithInt:0]
			   forKey:@"attacksLeftThisRound"];
	}
	NSManagedObject *spellClass=[tempSpellClass valueForKey:@"spellClass"];
	//NSLog(@"spellClass=%@",spellClass);
	NSManagedObject *spell=[spellClass valueForKey:@"spell"];
	int level=[[spellClass valueForKey:@"level"] intValue];
	//NSLog(@"level=%d",level);
	int levelCastAt=level;
	if([tempSpellClass valueForKey:@"castAtLevelTemp"]!=nil){
		levelCastAt=[[tempSpellClass valueForKey:@"castAtLevelTemp"] intValue];
	}
	//NSLog(@"levelCastAt=%d",levelCastAt);
	NSArray *feats=[[[tempSpellClass valueForKey:@"featsTemp"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"spellKey like[c] \"Caster Level\""]];
	int i;
	for(i=0;i<[feats count];i++){
		NSManagedObject *feat=[feats objectAtIndex:i];
		if([FeatActions xValueInUse:feat]){
			level=level+[[feat valueForKey:@"xValue"] intValue];
		}else{
			level=[FeatActions processValue:level
								 byModifier:[feat valueForKey:@"spellMod"]];
		}
	}
	//now remove one from level count and memorised spell if needed.
	NSManagedObject *characterClass;
	int casterLevel;
	if(row<c1){
		characterClass=[obj valueForKey:@"characterClass1"];
		casterLevel=[[obj valueForKey:@"charClassLvl1"] intValue];
	}else if(row<c1+c2){
		characterClass=[obj valueForKey:@"characterClass2"];
		casterLevel=[[obj valueForKey:@"charClassLvl2"] intValue];
	}else{
		characterClass=[obj valueForKey:@"characterClass3"];
		casterLevel=[[obj valueForKey:@"charClassLvl3"] intValue];
	}
	//NSLog(@"check arcane spell failure");
	NSManagedObject *spellLevel=[[[[obj valueForKey:@"spellLevel"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"characterClass.name like[c] \"%@\" AND level==%d",[characterClass valueForKey:@"name"],levelCastAt]]] objectAtIndex:0];
	//NSLog(@"spellLevelObject=%@",spellLevel);
	//now create a currentSpell, duplicated further up for some ms characters.
	NSManagedObject *cs=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentSpell"]
								 insertIntoManagedObjectContext:mObjC];
	[cs setValue:spellClass
		  forKey:@"spellClass"];
	//NSLog(@"characterClass=%@",characterClass);
	[cs setValue:characterClass
		  forKey:@"characterClass"];
	[cs setValue:obj
		  forKey:@"caster"];
	[cs setValue:[NSNumber numberWithInt:casterLevel]
		  forKey:@"casterLevel"];
	[cs setValue:[NSNumber numberWithInt:level]
		  forKey:@"spellLevel"];
	[cs setValue:spellLevel
		  forKey:@"spellLevelObj"];
	[cs setValue:[tempSpellClass valueForKey:@"featsTemp"]//gets the metamagic feats.
		  forKey:@"feat"];
	//add concentrating to it.
	[cs setValue:[NSNumber numberWithBool:[[NSNumber numberWithInt:[toConcentrate state]] boolValue]]
		  forKey:@"isConcentrating"];
	//check if class arcane (for arcane spell failure)
	if(![[characterClass valueForKey:@"divineSpell"] boolValue]){
		int arcaneSpellFailure=[[obj valueForKey:@"arcaneSpellFailure"] intValue];
		if(arcaneSpellFailure>0){
			int diceRoll=[RandomNumbers randomIntUpTo:100];
			if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
				NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d (%d needed) to check arcane spell failure for %@.",diceRoll,arcaneSpellFailure,[obj valueForKey:@"name"]];
				[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
							   forKey:@"eventLog"];
			}
			if(diceRoll<=arcaneSpellFailure){
				[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
							   forKey:@"currentCharacter"];
				[cs setValue:[NSString stringWithFormat:@"%@ has failed to cast the spell %@ due to arcane spell failure.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]
					  forKey:@"eventResult"];
				[self setupBattleDisplayWithMessage:nil];
				return;
			}
		}
		//NSLog(@"second half to start");
		[self secondHalfOfSpellWithCurrentSpell:cs
									  overwrite:NO];
		return;
	}
	//check if cleric and a heal/harm spell or druid and a summoning spell.
	if(([[characterClass valueForKey:@"healOrHarmSpontaneous"] boolValue] && (([[obj valueForKey:@"turnUndead"] boolValue] && [[spell valueForKey:@"subtype"] isEqualToString:@"Healing"]) || (![[obj valueForKey:@"turnUndead"] boolValue] && [[spell valueForKey:@"type"] intValue]==1))) || ([[characterClass valueForKey:@"summoningSpontaneous"] boolValue]  && [[spell valueForKey:@"type"] intValue]==3)){
			//check if native spells left.
		NSMutableSet *memSpells=[NSMutableSet setWithArray:[[[spellLevel valueForKey:@"memorisedSpell"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"castable==1"]]];
		NSMutableSet *spellsMemorisedSpells=[NSMutableSet setWithCapacity:1];
		NSArray *spellClasses=[[spell valueForKey:@"spellClass"] allObjects];
		int i;
		for(i=0;i<[spellClasses count];i++){
			[spellsMemorisedSpells unionSet:[[spellClasses objectAtIndex:i] valueForKey:@"memorisedSpell"]];
		}
		[memSpells intersectSet:spellsMemorisedSpells];
		if([memSpells count]==0){
			//display overwrite spell screen.
			//NSLog(@"overwrite to display");
			int i;
			for(i=0;i<[charactersSpellClasses count];i++){
				[mObjC deleteObject:[charactersSpellClasses objectAtIndex:i]];
			}
			[charactersSpellClasses removeAllObjects];
			//NSLog(@"levelCastAt=%d",levelCastAt);
			[self setupCharactersSpellsForChar:obj
								  forOverwrite:YES
							   startingAtLevel:levelCastAt];
			//NSLog(@"charactersSpells.count=%d",[charactersSpells count]);
			[spellOverwriteBlurb setStringValue:[NSString stringWithFormat:@"%@ hasn't memorised any more instances of the spell %@, please choose a spell below for %@ to overwrite instead.",[obj valueForKey:@"name"],[spell valueForKey:@"name"],[AbilityChanged getTPSGenderOfCharacter:obj]]];
			[spellOverwriteTable reloadData];
			//display the panel.
			NSWindow *displayScreen;
			if(ms){
				displayScreen=mainScreen;
			}else{
				displayScreen=battleScreen;
			}
			[NSApp beginSheet:spellOverwritePanel
			   modalForWindow:displayScreen
				modalDelegate:self
			   didEndSelector:@selector(spellOverwritePanelDidEnd:returnCode:currentSpell:)
				  contextInfo:cs];
			return;
		}
	}
	//NSLog(@"second half to start");
	[self secondHalfOfSpellWithCurrentSpell:cs
								  overwrite:NO];
}
-(IBAction)spellOverwritePanelCancelled:(id)sender{
	[NSApp endSheet:spellOverwritePanel returnCode:-1];
}
-(IBAction)spellOverwritePanelEnded:(id)sender{
	[NSApp endSheet:spellOverwritePanel returnCode:0];
}
-(void)spellOverwritePanelDidEnd:(NSWindow *)panel
					  returnCode:(int)returnCode
					currentSpell:(NSManagedObject *)currentSpell{
	[spellOverwritePanel orderOut:self];
	if(returnCode==-1){
		int i;
		for(i=0;i<[charactersSpellClasses count];i++){
			[mObjC deleteObject:[charactersSpellClasses objectAtIndex:i]];
		}
		[charactersSpellClasses removeAllObjects];
		[self setupBattleDisplayWithMessage:nil];
		return;
	}
	NSManagedObject *obj=[currentSpell valueForKey:@"caster"];
	//get the new spell.
	int row=[spellOverwriteTable selectedRow];
	
	NSManagedObject *tempSpellClass=[charactersSpellClasses objectAtIndex:row];
	NSManagedObject *spellClass=[tempSpellClass valueForKey:@"spellClass"];
	int level=[[[self tableView:spellOverwriteTable
	 objectValueForTableColumn:[[spellOverwriteTable tableColumns] objectAtIndex:0]
						   row:row] string] intValue];
	NSManagedObject *characterClass=[currentSpell valueForKey:@"characterClass"];
	//get the new spellLevel
	NSManagedObject *spellLevel=[[[[obj valueForKey:@"spellLevel"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"characterClass.name==\"%@\" AND level==%d",[characterClass valueForKey:@"name"],level]]] objectAtIndex:0];
	//setup current spell.
	[currentSpell setValue:spellClass
					forKey:@"overwrittenSpellClass"];
	[currentSpell setValue:spellLevel
					forKey:@"spellLevelOverwrite"];
	//NSLog(@"about to start part 2");
	[self secondHalfOfSpellWithCurrentSpell:currentSpell
								  overwrite:YES];
}
-(void)secondHalfOfSpellWithCurrentSpell:(NSManagedObject *)cs
							   overwrite:(BOOL)overwrite{
	//NSLog(@"second half begun");
	NSManagedObject *spellClass=[cs valueForKey:@"spellClass"];
	NSManagedObject *spell=[spellClass valueForKey:@"spell"];
	NSManagedObject *obj=[cs valueForKey:@"caster"];
	int casterLevel=[[cs valueForKey:@"casterLevel"] intValue];
	NSManagedObject *characterClass=[cs valueForKey:@"characterClass"];
	NSManagedObject *spellLevel=[cs valueForKey:@"spellLevelObj"];
	BOOL ms=[mainScreen isVisible];
	//second half.
	//take one off relevent counters for spells per day.
	[spellLevel setValue:[NSNumber numberWithInt:[[spellLevel valueForKey:@"spellsLeft"] intValue]-1]
				  forKey:@"spellsLeft"];
	[spellLevel setValue:[NSNumber numberWithInt:[[spellLevel valueForKey:@"spellsCast"] intValue]+1]
				  forKey:@"spellsCast"];
	//if a class that memorises spells.
	if(![[characterClass valueForKey:@"allSpontaneous"] boolValue]){
		//NSLog(@"not spontaneous");
		//get the memorised spell (an object from the union of mem spells from the spell and mem spells from the spell level)
		NSMutableSet *memSpells;
		if(overwrite){
			memSpells=[NSMutableSet setWithArray:[[[[cs valueForKey:@"spellLevelOverwrite"] valueForKey:@"memorisedSpell"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"castable==1"]]];
			[memSpells intersectSet:[[cs valueForKey:@"overwrittenSpellClass"] valueForKey:@"memorisedSpell"]];
		}else{
			memSpells=[NSMutableSet setWithArray:[[[spellLevel valueForKey:@"memorisedSpell"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"castable==1"]]];
			//NSLog(@"memSpells=%@",memSpells);
			//NSLog(@"memorisedSpellClass=%@",[spellClass valueForKey:@"memorisedSpell"]);
			[memSpells intersectSet:[spellClass valueForKey:@"memorisedSpell"]];
		}
		NSManagedObject *aMemSpell=[memSpells anyObject];
		//NSLog(@"aMemSpell=%@",aMemSpell);
		if([[aMemSpell valueForKey:@"domain"] boolValue]){
			[spellLevel setValue:[NSNumber numberWithInt:[[spellLevel valueForKey:@"spellsLeft"] intValue]+1]
						  forKey:@"spellsLeft"];
			[spellLevel setValue:[NSNumber numberWithInt:[[spellLevel valueForKey:@"spellsCast"] intValue]-1]
						  forKey:@"spellsCast"];
			[spellLevel setValue:[NSNumber numberWithBool:YES]
						  forKey:@"castDomainSpellToday"];
		}
		[aMemSpell setValue:[NSNumber numberWithBool:NO]
					 forKey:@"castable"];
	}
	//NSLog(@"set up casts/day");
	if(ms){
		//NSLog(@"a main screen spell");
		NSArray *feats=[[cs valueForKey:@"feat"] allObjects];
		//repeat for battle spells in runSpellWithCurrentSpell
		NSString *range;
		NSString *ranLabel=@"";
		if([[spell valueForKey:@"range"] isEqualToString:@"Personal"] || [[spell valueForKey:@"range"] isEqualToString:@"Touch"]){
			range=[spell valueForKey:@"range"];
		}else{
			range=[NSString stringWithFormat:@"%d",[SpellMethods rollDiceForSpell:spell
																		withFeats:feats
																		   forKey:@"ran"
																		 forLevel:casterLevel]];
			//set up range label, space added so that blank range label doesn't introduce double space.
			if([[spell valueForKey:@"ranMeasuredIn"] intValue]==0){
				ranLabel=@" feet";
			}else{
				ranLabel=@" miles";
			}
		}
		int duration=[SpellMethods rollDiceForSpell:spell
										  withFeats:feats
											 forKey:@"dur"
										   forLevel:casterLevel];
		if([[spell valueForKey:@"durPermanent"] boolValue]){
			duration=-1;
		}
		//set up duration label.
		NSString *durLabel;
		if([[spell valueForKey:@"durMeasuredIn"] intValue]==0){
			durLabel=@"rounds";
		}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==1){
			durLabel=@"minutes";
		}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==2){
			durLabel=@"hours";
		}else{
			durLabel=@"days";
		}
		if(([[spell valueForKey:@"durInstantaneous"] boolValue] || [[spell valueForKey:@"durPermanent"] boolValue]) && [[spell valueForKey:@"type"] intValue]<3 && ([[spell valueForKey:@"subtype"] isEqualToString:@"Healing"] || [[spell valueForKey:@"subtype"] isEqualToString:@"Damage"])){
			//more precise checker needed.
			//NSLog(@"can display target sheet");
			if([[spell valueForKey:@"range"] isEqualToString:@"Personal"]){
				NSManagedObject *st=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"SpellTarget"]
											 insertIntoManagedObjectContext:mObjC];
				[st setValue:obj
					  forKey:@"character"];
				[st setValue:[obj valueForKey:@"name"]
					  forKey:@"name"];
				[cs setValue:[NSSet setWithObject:st]
					  forKey:@"spellTarget"];
				NSString *message=[self processEffectFromCurrentSpell:cs
															 onSpellTarget:st];
				[mObjC deleteObject:cs];
				//log message.
				[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
							   forKey:@"eventLog"];
				NSBeginInformationalAlertSheet(@"Spell Result", @"Continue", nil, nil, mainScreen, self,nil,nil,NULL,message);
			}else{
				[self displaySpellTargetSheetForCurrentSpell:cs
												 forDuration:duration
											forDurationLabel:durLabel
													forRange:range
											   forRangeLabel:ranLabel
											  forCustomBlurb:NO];
			}
		}else{
			[mObjC deleteObject:cs];
			NSString *durString;
			if(duration==0){
				durString=@"Instant";
			}else if(duration==-1){
				durString=@"Permanent";
			}else{
				durString=[NSString stringWithFormat:@"%d %@",duration,durLabel];
			}
			if([[spell valueForKey:@"areaOfEffectOn"] boolValue] || [[spell valueForKey:@"type"] intValue]>2 || [[spell valueForKey:@"subtype"] isEqualToString:@"Feat"] || [[spell valueForKey:@"subtype"] isEqualToString:@"Neither"]){
				//log message.
				NSString *message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@. It has a range of %@%@ and a duration of %@.",[obj valueForKey:@"name"],[spell valueForKey:@"name"],range,ranLabel,durString];
				[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
							   forKey:@"eventLog"];
				NSBeginInformationalAlertSheet(@"Spell Result", @"Continue", nil, nil, mainScreen, self,nil,nil,NULL,message);
			}else{
				int noa=[SpellMethods rollDiceForSpell:spell
											 withFeats:feats
												forKey:@"noa"
											  forLevel:casterLevel];
				//just to get the English correct.
				NSString *message;
				if(noa==1){
					message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@. It has a range of %@%@ and a duration of %@, it also causes 1 attack.",[obj valueForKey:@"name"],[spell valueForKey:@"name"], range, ranLabel, durString];
				}else{
					message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@. It has a range of %@%@ and a duration of %@, it also causes %d attacks.",[obj valueForKey:@"name"],[spell valueForKey:@"name"],range,ranLabel,durString,noa];
				}
				[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
							   forKey:@"eventLog"];
				NSBeginInformationalAlertSheet(@"Spell Result", @"Continue", nil, nil, mainScreen, self,nil,nil,NULL,message);
			}
		}
		int i;
		for(i=0;i<[charactersSpellClasses count];i++){
			[mObjC deleteObject:[charactersSpellClasses objectAtIndex:i]];
		}
		[charactersSpellClasses removeAllObjects];
		if(ssController!=nil){
			[ssController reloadSpellTables];
		}
		return;
	}
	//NSLog(@"battle spell");
	//now back to in battle spell stuff.
	//nullify exsisting "current damage", as it doesn't affect spells we haven't started casting yet.
	[obj setValue:nil
		   forKey:@"targetOfCurrentEvent"];
	//NSLog(@"switch about to start");
	switch([[spell valueForKey:@"castingTime"] intValue]){
		case 0:
			//cast spell immediately free action spells don't suffer attacks of opportunity.
			[self runSpellWithCurrentSpell:cs];
			return;
		case 3:
			//cast spell later.
			[cs setValue:[NSNumber numberWithInt:[[battleStore valueForKey:@"currentRound"] intValue]+[[spell valueForKey:@"castingTimeCustom"] intValue]]
				  forKey:@"runsOutInRound"];
			[cs setValue:[NSNumber numberWithBool:YES]
				  forKey:@"lastsMultipleRounds"];
			break;
		default:
			break;
	}
	//NSLog(@"we are still here");
	int i;
	for(i=0;i<[charactersSpellClasses count];i++){
		[mObjC deleteObject:[charactersSpellClasses objectAtIndex:i]];
	}
	[charactersSpellClasses removeAllObjects];
	[self setupAttackOOforAction:[NSString stringWithFormat:@"casting the spell %@",[spell valueForKey:@"name"]]];
}
-(void)runSpellWithCurrentSpell:(NSManagedObject *)currentSpell{
	NSString *message=[self runningSpellWithCurrentSpell:currentSpell];
	if(![message isEqualToString:@"No Battle Display Setup"]){
		if(currentSpell!=nil){
			[currentSpell setValue:message
							forKey:@"resultMessage"];
			[currentSpell setValue:[NSNumber numberWithBool:YES]
							forKey:@"processed"];
			[self setupBattleDisplayWithMessage:nil];
		}else{
			[self setupBattleDisplayWithMessage:message];
		}
	}
}
-(NSString *)runningSpellWithCurrentSpell:(NSManagedObject *)currentSpell{
	//NSLog(@"run spell with current spell");
	NSString *message;
	NSManagedObject *spell=[[currentSpell valueForKey:@"spellClass"] valueForKey:@"spell"];
	NSManagedObject *obj=[currentSpell valueForKey:@"caster"];
	NSArray *feats=[[currentSpell valueForKey:@"feat"] allObjects];
	//check concentration.
	if(![self rollConcentrationForCurrentSpell:currentSpell]){
		message=[NSString stringWithFormat:@"%@ has failed a concentration check on the spell %@",[obj valueForKey:@"name"],[spell valueForKey:@"name"]];
		return message;
	}
	//create active spell as required.
	//check character still alive.
	if([[obj valueForKey:@"currentHP"] intValue]<=0){
		message=[NSString stringWithFormat:@"%@ has died and so has failed to cast the spell %@",[obj valueForKey:@"name"],[spell valueForKey:@"name"]];
		NSString *message2=[self deathCheck:obj];
		if(message2!=nil){
			if([message isEqualToString:@""]){
				message=message2;
			}else{
				[message stringByAppendingFormat:@"\n%@",message2];
			}
		}
		[mObjC deleteObject:currentSpell];
		return message;
		
	}
	int casterLevel=[[currentSpell valueForKey:@"casterLevel"] intValue];
	//repeated for main screen spells in spell chosen did end...
	NSString *range;
	NSString *ranLabel=@"";
	if([[spell valueForKey:@"range"] isEqualToString:@"Personal"] || [[spell valueForKey:@"range"] isEqualToString:@"Touch"]){
		range=[spell valueForKey:@"range"];
	}else{
		range=[NSString stringWithFormat:@"%d",[SpellMethods rollDiceForSpell:spell
																	withFeats:feats
																	   forKey:@"ran"
																	 forLevel:casterLevel]];
		//set up range label, space added so that blank range label doesn't introduce double space.
		if([[spell valueForKey:@"ranMeasuredIn"] intValue]==0){
			ranLabel=@" feet";
		}else{
			ranLabel=@" miles";
		}
	}
	int duration=0;
	//set up duration label.
	NSString *durLabel;
	if([[spell valueForKey:@"durMeasuredIn"] intValue]==0){
		durLabel=@"rounds";
	}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==1){
		durLabel=@"minutes";
	}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==2){
		durLabel=@"hours";
	}else{
		durLabel=@"days";
	}
	NSManagedObject *as;
	if(![[spell valueForKey:@"durInstantaneous"] boolValue]){
		as=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"ActiveSpell"]
									 insertIntoManagedObjectContext:mObjC];
		[as setValue:obj
			  forKey:@"caster"];
		[as setValue:spell
			  forKey:@"spell"];
		[as setValue:currentSpell
			  forKey:@"currentSpell"];
		[as setValue:[currentSpell valueForKey:@"isConcentrating"]
			  forKey:@"isConcentrating"];
		duration=[SpellMethods rollDiceForSpell:spell
									  withFeats:feats
										 forKey:@"dur"
									   forLevel:casterLevel];
		if([[spell valueForKey:@"durPermanent"] boolValue]){
			duration=-1;
		}
		//to cope with minutes, hours etc.
		int duration2=duration;
		if([durLabel isEqualToString:@"minutes"]){
			duration2=duration2*10;
		}else if([durLabel isEqualToString:@"hours"]){
			duration2=duration2*600;
		}else if([durLabel isEqualToString:@"days"]){
			duration2=duration2*14400;
		}
		[as setValue:[NSNumber numberWithInt:[[battleStore valueForKey:@"currentRound"] intValue]+duration2]
			  forKey:@"lastsUntilRound"];
	}
	//check what to do with the spell now.
	//NSLog(@"spell.type=%d",[[spell valueForKey:@"type"] intValue]);
	if([[spell valueForKey:@"type"] intValue]==3){
		NSLog(@"summoner");
		[self editCharactersCode];
		NSString *durString;
		if(duration==0){
			durString=@"Instant";
		}else if(duration==-1){
			durString=@"Permanent";
		}else{
			durString=[NSString stringWithFormat:@"%d %@",duration,durLabel];
		}
		message=[NSString stringWithFormat:@"%@ has successfully cast the summoning spell %@. It has a range of %@%@ and a duration of %@. Now we are returning to the character screen so the summoned characters can be added.",[obj valueForKey:@"name"],[spell valueForKey:@"name"],range,ranLabel,durString];
		[battleStore setValue:[NSNumber numberWithBool:YES]
					   forKey:@"returnedFromSummoning"];
		if(![[spell valueForKey:@"durInstantaneous"] boolValue] && ![[spell valueForKey:@"durPermanent"] boolValue]){
			[battleStore setValue:[NSSet setWithObject:as]
						   forKey:@"activeSpell"];
		}
		return message;
	}else if([[spell valueForKey:@"type"] intValue]==4){
		if([[spell valueForKey:@"returnToCharScreen"] boolValue]){
			[self editCharactersCode];
			NSString *durString;
			if(duration==0){
				durString=@"Instant";
			}else if(duration==-1){
				durString=@"Permanent";
			}else{
				durString=[NSString stringWithFormat:@"%d %@",duration,durLabel];
			}
			message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@, it has a range of %@%@ and duration of %@, returning to the character screen so the effects can be applied",[obj valueForKey:@"name"],[spell valueForKey:@"name"],range,ranLabel,durString];
			return message;
		}else{
			message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@",[obj valueForKey:@"name"],[spell valueForKey:@"name"]];
			return message;
		}
	}else{
		if(![[spell valueForKey:@"durInstantaneous"] boolValue]){
			//set up some additional properties for activeSpell.
			[as setValue:[currentSpell valueForKey:@"abilityBonus"]
				  forKey:@"abilityBonus"];
			[as setValue:[currentSpell valueForKey:@"casterLevel"]
				  forKey:@"casterLevel"];
			[as setValue:[currentSpell valueForKey:@"spellLevel"]
				  forKey:@"spellLevel"];
			[as setValue:[currentSpell valueForKey:@"feat"]
				  forKey:@"feat"];
			[as setValue:range
				  forKey:@"range"];
			[as setValue:ranLabel
				  forKey:@"rangeLabel"];
		}
		if([[spell valueForKey:@"range"] isEqualToString:@"Personal"]){
			//cast spell on self only.
			NSManagedObject *st=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"SpellTarget"]
										 insertIntoManagedObjectContext:mObjC];
			[st setValue:obj
				  forKey:@"character"];
			[st setValue:[obj valueForKey:@"name"]
				  forKey:@"name"];
			[currentSpell setValue:[NSSet setWithObject:st]
							forKey:@"spellTarget"];
			NSString *message=[self processEffectFromCurrentSpell:currentSpell
														 onSpellTarget:st];
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
				message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@.\nThis causes the effect:%@\n%@",[obj valueForKey:@"name"],[spell valueForKey:@"name"],[spell valueForKey:@"featDescription"],message];
			}else{
				message=[NSString stringWithFormat:@"%@ has successfully cast the spell %@.\n%@",[obj valueForKey:@"name"],[spell valueForKey:@"name"],message];
			}
			return message;
		}else{
			[self displaySpellTargetSheetForCurrentSpell:currentSpell
											 forDuration:duration
										forDurationLabel:durLabel
												forRange:range
										   forRangeLabel:ranLabel
										  forCustomBlurb:NO];
			return @"No Battle Display Setup";
		}		
	}
	return message;
}
-(void)displaySpellTargetSheetForCurrentSpell:(NSManagedObject *)currentSpell
								  forDuration:(int)duration
							 forDurationLabel:(NSString *)durLabel
									 forRange:(NSString *)range
								forRangeLabel:(NSString *)ranLabel
							   forCustomBlurb:(BOOL)blurb{
	NSManagedObject *obj=[currentSpell valueForKey:@"caster"];
	NSManagedObject *spell=[[currentSpell valueForKey:@"spellClass"] valueForKey:@"spell"];
	int casterLevel=[[currentSpell valueForKey:@"casterLevel"] intValue];
	NSArray *feats=[[currentSpell valueForKey:@"feat"] allObjects];
	//NSLog(@"displaying spell target sheet");
	//display target sheet.
	if(![mainScreen isVisible]){
		if([[spell valueForKey:@"areaOfEffectOn"] boolValue] || [[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember==1 OR enemyPartyMember==1"]];
		}else if([[obj valueForKey:@"mainPartyMember"] boolValue] && [[obj valueForKey:@"enemyPartyMember"] boolValue]){
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Healing"] || [[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
				[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember==1 OR enemyPartyMember==1"]];
			}else{
				[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id!=%d AND (mainPartyMember==1 OR enemyPartyMember==1)",[[obj valueForKey:@"id"] intValue]]]];
			}
		}else if(([[obj valueForKey:@"mainPartyMember"] boolValue] && [[spell valueForKey:@"type"] intValue]!=0) ||([[spell valueForKey:@"type"] intValue]==0 && [[obj valueForKey:@"enemyPartyMember"] boolValue])){
			[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"enemyPartyMember==1"]];
		}else{
			[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember==1"]];
		}
	}else{
		if([[mainCharacterController arrangedObjects] count]>[[characterController arrangedObjects] count]){
			[characterController removeObjects:[characterController arrangedObjects]];
			[characterController addObjects:[mainCharacterController arrangedObjects]];
		}
		if( [[spell valueForKey:@"areaOfEffectOn"] boolValue] || [[spell valueForKey:@"subtype"] isEqualToString:@"Healing"] || [[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"template==0"]];
		}else{
			[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"template==0 AND id!=%d",[[obj valueForKey:@"id"] intValue]]]];
		}
	}
	if([[spell valueForKey:@"areaOfEffectOn"] boolValue] || [[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
		[noOfAttacksTF setStringValue:@"Inf."];
		[currentSpell setValue:[NSNumber numberWithInt:0]
						forKey:@"noOfAttacks"];
	}else{
		if([[spell valueForKey:@"type"] intValue]<2){
			[noOfAttacksTF setIntValue:1];
			[currentSpell setValue:[NSNumber numberWithInt:1]
							forKey:@"noOfAttacks"];
		}else{
			int noa=[SpellMethods rollDiceForSpell:spell
										 withFeats:feats
											forKey:@"noa"
										  forLevel:casterLevel];
			[noOfAttacksTF setIntValue:noa];
			[currentSpell setValue:[NSNumber numberWithInt:noa]
							forKey:@"noOfAttacks"];
		}
	}
	if(!blurb){
		[spellTargetBlurb setStringValue:[NSString stringWithFormat:@"%@ has successfully cast the spell %@ please choose who it is targetting.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
	}
	//set range on display
	[rangeTarTF setStringValue:range];
	if([ranLabel isEqualToString:@""]){
		[rangeLabel setStringValue:@"range"];
	}else{//leading space removed from ranLabel.
		[rangeLabel setStringValue:[NSString stringWithFormat:@"range (%@)",[ranLabel substringFromIndex:1]]];
	}
	//set duration on display.
	if(duration==0){
		[durationTarTF setStringValue:@"Instant"];
		[durationLabel setStringValue:@"duration"];
	}else if(duration==-1){
		[durationTarTF setStringValue:@"Permanent"];
		[durationLabel setStringValue:@"duration"];
	}else{
		[durationTarTF setIntValue:duration];
		[durationLabel setStringValue:[NSString stringWithFormat:@"duration (%@)",durLabel]];
	}
	//area of effect to display
	if([[spell valueForKey:@"areaOfEffectOn"] boolValue]){
		[aoeInvisibox setIntValue:1];
		[aoeTarSize setStringValue:[NSString stringWithFormat:@"%dft",[[spell valueForKey:@"areaOfEffectSize"] intValue]]];
		if([[spell valueForKey:@"areaOfEffect"] intValue]==0){
			[aoeTarType setStringValue:@"Circle"];
			[aoeTarSizeLabel setStringValue:@"Radius"];
		}else{
			[aoeTarSizeLabel setStringValue:@"Length"];
			if([[spell valueForKey:@"areaOfEffect"] intValue]==1){
				[aoeTarType setStringValue:@"Cone"];
			}else{
				[aoeTarType setStringValue:@"Line"];
			}
		}
	}else{
		[aoeTarSizeLabel setStringValue:@"Length"];
		[aoeTarSize setStringValue:@"N/A"];
		[aoeTarType setStringValue:@"None"];
		[aoeInvisibox setIntValue:0];
	}
	[damageTarTF setStringValue:@""];
	[damageTarTF setStringValue:[SpellMethods processSpell:spell
												 withFeats:feats
													forKey:@"dam"
												  forLevel:casterLevel]];
	[spellTargetTable reloadData];
	[spellTargetsChooserTable reloadData];
	//setup add/remove buttons
	[addToSpellTargetsButton setEnabled:YES];
	[removeFromSpellTargetsButton setEnabled:NO];
	//NSLog(@"target sheet to display");
	if([mainScreen isVisible]){
		[NSApp beginSheet:spellTargetSheet
		   modalForWindow:mainScreen
			modalDelegate:self
		   didEndSelector:@selector(spellTargetPanelDidEnd:returnCode:currentSpell:)
			  contextInfo:currentSpell];
	}else{
		[NSApp beginSheet:spellTargetSheet
		   modalForWindow:battleScreen
			modalDelegate:self
		   didEndSelector:@selector(spellTargetPanelDidEnd:returnCode:currentSpell:)
			  contextInfo:currentSpell];
	}
}
-(IBAction)addSpellTarget:(id)sender{
	if([[characterController selectedObjects] count]==0)
		return;
	NSManagedObject *st=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"SpellTarget"]
								 insertIntoManagedObjectContext:mObjC];
	NSManagedObject *obj=[[characterController arrangedObjects] objectAtIndex:[spellTargetsChooserTable selectedRow]];
	[st setValue:obj
		  forKey:@"character"];
	[st setValue:[obj valueForKey:@"name"]
		  forKey:@"name"];
	[spellTargetController addObject:st];
	[spellTargetTable reloadData];
	//check if total number of targets found.
	int noOfTargets=[spellTargetTable numberOfRows];
	if(![[noOfAttacksTF stringValue] isEqualToString:@"Inf."]){
		if(noOfTargets>=[noOfAttacksTF intValue]){
			[addToSpellTargetsButton setEnabled:NO];
		}		
	}else{
		[addToSpellTargetsButton setEnabled:NO];
	}
	if(noOfTargets>0){
		[removeFromSpellTargetsButton setEnabled:YES];
		[continueFromSpellTargetsButton setEnabled:YES];
	}
	//check if need to disable button.
	if([aoeInvisibox intValue]==1){
		//check if character already has a target.
		[addToSpellTargetsButton setEnabled:NO];
	}
}
-(IBAction)removeSpellTarget:(id)sender{
	[spellTargetTableEdit setDelegate:nil];
	NSManagedObject *st=[[spellTargetController arrangedObjects] objectAtIndex:[spellTargetTable selectedRow]];
	NSManagedObject *obj=[st valueForKey:@"character"];
	[spellTargetController removeObject:st];
	[mObjC deleteObject:st];
	[spellTargetTable reloadData];
	//check if total number of targets found.
	int noOfTargets=[[spellTargetController arrangedObjects] count];
	if(![[noOfAttacksTF stringValue] isEqualToString:@"Inf."]){
		if(noOfTargets<[noOfAttacksTF intValue]){
			[addToSpellTargetsButton setEnabled:YES];
		}		
	}else{
		if([obj isEqualTo:[[characterController arrangedObjects] objectAtIndex:[spellTargetsChooserTable selectedRow]]]){
			[addToSpellTargetsButton setEnabled:YES];
		}
	}
	if(noOfTargets==0){
		[removeFromSpellTargetsButton setEnabled:NO];
		[continueFromSpellTargetsButton setEnabled:NO];
	}
	[spellTargetTableEdit setDelegate:self];
}
-(IBAction)continueFromSpellTargets:(id)sender{
	[spellTargetSheet orderOut:sender];
	[NSApp endSheet:spellTargetSheet returnCode:0];
}
-(IBAction)cancelFromSpellTargets:(id)sender{
	[spellTargetSheet orderOut:sender];
	[NSApp endSheet:spellTargetSheet returnCode:-1];
}
-(void)spellTargetPanelDidEnd:(NSWindow *)panel
				   returnCode:(int)returnCode
				 currentSpell:(NSManagedObject *)currentSpell{
	if(returnCode==-1){
		[mObjC deleteObject:currentSpell];
		if([mainScreen isVisible]){
			[characterController setFilterPredicate:nil];
		}
		[self setupBattleDisplayWithMessage:nil];
		return;
	}else if(returnCode==1){
		return;
	}else if(returnCode==2){
		NSArray *array=[[NSArray alloc] initWithObjects:spellTargetSheet,currentSpell,nil];
		if([mainScreen isVisible]){
			[NSApp beginSheet:infoPanel
			   modalForWindow:mainScreen
				modalDelegate:self
			   didEndSelector:@selector(playerInfoClosed:returnCode:contextInfo:)
				  contextInfo:array];
		}else{
			[NSApp beginSheet:infoPanel
			   modalForWindow:battleScreen
				modalDelegate:self
			   didEndSelector:@selector(playerInfoClosed:returnCode:contextInfo:)
				  contextInfo:array];
		}
		return;
	}
	//otherwise process.
	NSArray *arrayTargets=[[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"spellTarget" substitutionVariables:[NSDictionary dictionary]]
										 error:nil] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
	[currentSpell setValue:[NSSet setWithArray:arrayTargets]
					forKey:@"spellTarget"];
	int i;
	NSManagedObject *spell=[[currentSpell valueForKey:@"spellClass"] valueForKey:@"spell"];
	NSString *message=[NSString stringWithFormat:@"%@ has cast the spell %@",[[currentSpell valueForKey:@"caster"] valueForKey:@"name"],[spell valueForKey:@"name"]];
	if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
		message=[NSString stringWithFormat:@"%@\nThis causes the effect:%@",message,[spell valueForKey:@"featDescription"]];
	}
	for(i=0;i<[arrayTargets count];i++){
		message=[NSString stringWithFormat:@"%@\n%@",message,[self processEffectFromCurrentSpell:currentSpell onSpellTarget:[arrayTargets objectAtIndex:i]]];
	}
	if([mainScreen isVisible]){
		[characterController setFilterPredicate:nil];
		[mainCharacterController setFilterPredicate:nil];
	}else{
		//returns to the character screen if option chosen.
		if([[spell valueForKey:@"returnToCharScreen"] boolValue]){
			message=[message stringByAppendingString:@"\nNow returning to the character screen to finish off the spell casting."];
			[self editCharactersCode];
		}
	}
	[currentSpell setValue:message
					forKey:@"resultMessage"];
	[currentSpell setValue:[NSNumber numberWithBool:YES]
					forKey:@"processed"];
	[self setupBattleDisplayWithMessage:nil];
}
-(NSString *)processEffectFromCurrentSpell:(NSManagedObject *)currentSpell
							 onSpellTarget:(NSManagedObject *)spellTarget{
	NSManagedObject *obj2=[spellTarget valueForKey:@"character"];
	NSManagedObject *spell=[[currentSpell valueForKey:@"spellClass"] valueForKey:@"spell"];
	int spellLevel=[[currentSpell valueForKey:@"spellLevel"] intValue];
	NSManagedObject *obj=[currentSpell valueForKey:@"caster"];
	int casterLevel=[[currentSpell valueForKey:@"casterLevel"] intValue];
	NSArray *feats=[[currentSpell valueForKey:@"feat"] allObjects];
	NSString *className=[currentSpell valueForKey:@"theClassName"];
	//get ability bonus for save DC.
	int abilBonus;
	if([className isEqualToString:@"Wizard"]){
		abilBonus=[AbilityChanged scoreToBonus:[obj valueForKey:@"intelligence"]];
	}else if([className isEqualToString:@"Sorcerer"] || [className isEqualToString:@"Bard"]){
		abilBonus=[AbilityChanged scoreToBonus:[obj valueForKey:@"charisma"]];
	}else{
		abilBonus=[AbilityChanged scoreToBonus:[obj valueForKey:@"wisdom"]];
	}
	//enable required feats.
	[FeatActions setupFeatsForCaster:obj
						   forTarget:obj2
							 atRange:0
							   nowOn:YES];
	//check spell resistance.
	int sr=[[obj2 valueForKey:@"spellResistance"] intValue];
	if(sr !=0){
		int dieRoll=[RandomNumbers randomIntUpTo:20];
		int bonus=casterLevel+[[obj valueForKey:@"spellPenetration"] intValue];
		if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
			NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d to check %@'s spell against %@'s spell resistance (%d or die roll of 20 required).",dieRoll,bonus,[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],sr];
			[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
						   forKey:@"eventLog"];
		}
		if(dieRoll==1 || (dieRoll+bonus<sr && dieRoll !=20)){
			//failed
			//disable required feats.
			[FeatActions setupFeatsForCaster:obj
								   forTarget:obj2
									 atRange:0
									   nowOn:NO];
			return [NSString stringWithFormat:@"%@ has failed to overcome the spell resistance of %@.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"]];
		}
		[spellTarget setValue:[NSNumber numberWithBool:YES]
					   forKey:@"passesSpellResistance"];
	}
	//throw attack roll (if required)
	if([[spell valueForKey:@"attackRoll"] boolValue]){
		int enemyAC=[[obj2 valueForKey:@"armourClassTouch"] intValue];
		int attackBonus;
		if([[spell valueForKey:@"range"] isEqualToString:@"Touch"]){
			attackBonus=[[obj valueForKey:@"meleeAttackBonus"] intValue];
		}else{
			attackBonus=[[obj valueForKey:@"rangedAttackBonus"] intValue];
		}
		int dieRoll=[RandomNumbers randomIntUpTo:20];
		if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
			NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d to check %@'s spell's attack roll against %@ (%d or die roll of 20 required).",dieRoll,attackBonus,[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],enemyAC];
			[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
						   forKey:@"eventLog"];
		}
		if(dieRoll==1 || (dieRoll+attackBonus<enemyAC && dieRoll!=20)){
			//disable required feats.
			[FeatActions setupFeatsForCaster:obj
								   forTarget:obj2
									 atRange:0
									   nowOn:NO];
			return [NSString stringWithFormat:@"%@ has failed to hit %@ with the spell.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"]];
		}
		[spellTarget setValue:[NSNumber numberWithBool:YES]
					   forKey:@"passesAttackRoll"];
	}
	int damage=0;
	//roll saving throw
	int savePassed=-1;
	if([[spell valueForKey:@"saveEffect"] intValue]>0){
		int saveDC=spellLevel+10+[[spell valueForKey:@"saveMod"] intValue]+abilBonus+[[obj valueForKey:@"spellSaveModifier"] intValue];
		if([[spell valueForKey:@"saveType"] intValue]==0){
			savePassed=[SpellMethods rollASaveOfDC:saveDC
											ofType:@"Reflex"
												on:obj2];
		}else if([[spell valueForKey:@"saveType"] intValue]==1){
			savePassed=[SpellMethods rollASaveOfDC:saveDC
											ofType:@"Fortitude"
												on:obj2];
		}else if([[spell valueForKey:@"saveType"] intValue]==2){
			savePassed=[SpellMethods rollASaveOfDC:saveDC
											ofType:@"Will"
												on:obj2];
		}		
	}
	if(savePassed==0){
		[spellTarget setValue:[NSNumber numberWithBool:YES]
					   forKey:@"failsSavingThrow"];
	}
	if(savePassed!=1){
		if(![[spell valueForKey:@"durInstantaneous"] boolValue]){
			NSManagedObject *as=[currentSpell valueForKey:@"activeSpell"];
			NSMutableSet *set=[as valueForKey:@"target"];
			[set addObject:obj2];
			[as setValue:set
				  forKey:@"target"];
		}
	}
	//check if feat style or damage or healing.
	if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
		if(savePassed==1){
			//disable required feats.
			[FeatActions setupFeatsForCaster:obj
								   forTarget:obj2
									 atRange:0
									   nowOn:NO];
			return [NSString stringWithFormat:@"%@ has passed a saving throw against the spell and is unaffected.",[obj2 valueForKey:@"name"]];
		}
		//NSLog(@"about to apply 'feat'");
		//a "feat" style spell, and the saving throw is passed.
		[FeatActions processFeat:spell
						forKeyNo:1
						  onChar:obj2
						forwards:YES];
		[FeatActions processFeat:spell
						forKeyNo:2
						  onChar:obj2
						forwards:YES];
		[FeatActions processFeat:spell
						forKeyNo:3
						  onChar:obj2
						forwards:YES];
		[FeatActions processFeat:spell
						forKeyNo:4
						  onChar:obj2
						forwards:YES];
		[spellTarget setValue:[NSNumber numberWithBool:YES]
					   forKey:@"featEnabled"];
		[spellTarget setValue:[NSNumber numberWithBool:YES]
					   forKey:@"newFeatEnabled"];
		//set paralysis as required.
		if(savePassed!=1 && [[spell valueForKey:@"paralysesTargets"] boolValue]){
			[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"paralysed"] intValue]+1]
					forKey:@"paralysed"];
		}
		//disable required feats.
		[FeatActions setupFeatsForCaster:obj
							   forTarget:obj2
								 atRange:0
								   nowOn:NO];
		if(savePassed==-1){
			return [NSString stringWithFormat:@"%@ has been affected by the spell.",[obj2 valueForKey:@"name"]];
		}else{
			return [NSString stringWithFormat:@"%@ has failed a saving throw and has been affected by the spell.",[obj2 valueForKey:@"name"]];
		}
	}else if(![[spell valueForKey:@"subtype"] isEqualToString:@"Neither"]){
		//NSLog(@"not a feat.");
		damage=[SpellMethods rollDiceForSpell:spell
									withFeats:feats
									   forKey:@"dam"
									 forLevel:casterLevel
							   forSpellTarget:spellTarget];
		//log damage roll
		if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
			NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %@+%@ for damage by %@'s spell against %@",[spellTarget valueForKey:@"diceDamage"],[spellTarget valueForKey:@"bonusDamage"],[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
			[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
						   forKey:@"eventLog"];
		}
		//check if healing or damage.
		//NSLog(@"spell.name=%@",[spell valueForKey:@"name"]);
		if([[spell valueForKey:@"type"] intValue]==0){
			//NSLog(@"healing spell");
			[obj2 setValue:[NSNumber numberWithBool:YES]
					forKey:@"stable"];
			if([[obj2 valueForKey:@"currentHP"] intValue]+damage>=[[obj2 valueForKey:@"maxHP"] intValue]){//check damage doesn't bring HP to over 100%.
				[obj2 setValue:[obj2 valueForKey:@"maxHP"]
						forKey:@"currentHP"];
				return [NSString stringWithFormat:@"%@ has healed %@ to full health.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"]];
			}else{
				[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"currentHP"] intValue]+damage]
						  forKey:@"currentHP"];
				return [NSString stringWithFormat:@"%@ has healed %@ by %d hit points.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"],damage];
			}
		}else{
			//NSLog(@"damage spell");
			//now check saving throw.
			if(savePassed==1){
				if([[spell valueForKey:@"saveEffect"] intValue]==1){
					damage=damage/2;
				}else{
					damage=0;
				}
			}
			//now check immunities.
			damage=[self checkForImmunityOnCharacter:obj2
									  withDamageType:[spell valueForKey:@"damageType"]
									  withWeaponPlus:-1
										  withDamage:damage];
			[spellTarget setValue:[NSNumber numberWithInt:damage]
						   forKey:@"totalDamage"];
			int currentHP=[[obj2 valueForKey:@"currentHP"] intValue];
			//commit damage
			[obj2 setValue:[NSNumber numberWithInt:currentHP-damage]
					forKey:@"currentHP"];
			//set paralysis as required.
			if(savePassed!=1 && [[spell valueForKey:@"paralysesTargets"] boolValue]){
				[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"paralysed"] intValue]+1]
						forKey:@"paralysed"];
			}
			NSMutableString *message=[[NSMutableString alloc] initWithCapacity:50];
			[message appendFormat:@"%@",[obj2 valueForKey:@"name"]];
			if([[spell valueForKey:@"attackRoll"] boolValue]){
				[message appendString:@" was hit and"];
				if(savePassed==0){
					[message appendString:@" but"];
				}else if(savePassed==1){
					[message appendString:@" and"];
				}
			}
			if(savePassed==-1){
				if(damage==0){
					[message appendFormat:@" has suffered no damage and still has %d hit points.",[[obj2 valueForKey:@"currentHP"] intValue]];
				}else{
					[message appendFormat:@" has suffered %d damage taking %@ to %d hit points.",damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
				}
			}else if(savePassed==1){
				[message appendString:@" has passed a saving throw,"];
				if(damage==0){
					[message appendFormat:@" as a result %@ has suffered no damage and still has %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
				}else{
					[message appendFormat:@" As a result %@ has suffered %d damage taking %@ to %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
				}
			}else{
				[message appendString:@" has failed a saving throw."];
				if(damage==0){
					[message appendFormat:@" As a result %@ has suffered no damage and still has %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
				}else{
					[message appendFormat:@" As a result %@ has suffered %d damage taking %@ to %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
				}
			}
			//create a current damage object (as required).
			if(damage>0){
				NSManagedObject *cd=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentDamage"]
											 insertIntoManagedObjectContext:mObjC];
				[cd setValue:obj
					  forKey:@"caster"];
				[cd setValue:obj2
					  forKey:@"target"];
				[cd setValue:[NSNumber numberWithInt:damage]
					  forKey:@"damage"];
			}	
			//check if unconcious/dead
			if(currentHP>0 && currentHP-damage<=0){
				//unconcious/dead
				NSString *message2=[self deathCheck:obj2];
				if(message2!=nil){
					if([message isEqualToString:@""]){
						[message appendString:message2];
					}else{
						[message appendFormat:@"\n%@",message2];
					}
				}
				//give XP to killing characters party.
				/*if([[obj valueForKey:@"mainPartyMember"] boolValue] && [[obj2 valueForKey:@"enemyPartyMember"] boolValue]){
					//party 1 gets XP
					[self grantXPToParty:1
							 forTargetCR:[[obj2 valueForKey:@"challengeRating"] doubleValue]];
				}else if([[obj valueForKey:@"enemyPartyMember"] boolValue] && [[obj2 valueForKey:@"mainPartyMember"] boolValue]){
					//party 2 gets XP
					[self grantXPToParty:2
							 forTargetCR:[[obj2 valueForKey:@"challengeRating"] doubleValue]];
				}*/				
			}
			//disable required feats.
			[FeatActions setupFeatsForCaster:obj
								   forTarget:obj2
									 atRange:0
									   nowOn:NO];
			return message;
		}
	}
	//disable required feats.
	[FeatActions setupFeatsForCaster:obj
						   forTarget:obj2
							 atRange:0
							   nowOn:NO];
	return @"";
}

-(BOOL)rollConcentrationForCurrentSpell:(NSManagedObject *)currentSpell{
	NSManagedObject *obj=[currentSpell valueForKey:@"caster"];
	int spellLevel=[[currentSpell valueForKey:@"spellLevel"] intValue];
	return [self rollConcentrationForCharacter:obj
								 forSpellLevel:spellLevel];
}
-(BOOL)rollConcentrationForCharacter:(NSManagedObject *)obj
					   forSpellLevel:(int)spellLevel{
	NSArray *array=[[obj valueForKey:@"targetOfCurrentEvent"] allObjects];
	int i;
	int damage=0;
	for(i=0;i<[array count];i++){
		NSManagedObject *ce=[array objectAtIndex:i];
		if([[ce entity] isEqualTo:[[model entitiesByName]  objectForKey:@"CurrentDamage"]]){
			damage=damage+[[ce valueForKey:@"damage"] intValue];
		}
	}
	//no conc test to run if no damage.
	if(damage==0){
		return YES;
	}
	int dc=10+spellLevel+damage;
	NSManagedObject *skill=[[[[obj valueForKey:@"skills"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"name==\"Concentration\""]]] objectAtIndex:0];
	
	int diceRoll=[RandomNumbers randomIntUpTo:20];
	int bonus=[[skill valueForKey:@"total"] intValue];
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
		NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d for a concentration check for %@ (%d required to pass).",diceRoll,bonus,[obj valueForKey:@"name"],dc];
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
					   forKey:@"eventLog"];
	}
	if(diceRoll==1){
		//NSLog(@"failed conc test");
		return NO;
	}else if(diceRoll==20){
		return YES;
	}else{
		if(diceRoll+bonus>=dc){
			//NSLog(@"passed %d+%d (dc=%d)",diceRoll,[[skill valueForKey:@"total"] intValue],dc);
			return YES;
		}else{
			//NSLog(@"failed %d+%d (dc=%d)",diceRoll,[[skill valueForKey:@"total"] intValue],dc);
			return NO;
		}
	}
}
-(void)processSpellsToCastTable{
	//NSLog(@"spells to cast table");
	int row=[spellsToCastTable selectedRow];
	if(row==-1)
		return;
	//main method.
	NSManagedObject *tempSpellClass=[charactersSpellClasses objectAtIndex:row];
	NSManagedObject *spellClass=[tempSpellClass valueForKey:@"spellClass"];
	NSManagedObject *spell=[spellClass valueForKey:@"spell"];
	NSArray *feats=[[tempSpellClass valueForKey:@"featsTemp"] allObjects];
	NSManagedObject *obj;
	if([mainScreen isVisible]){
		if([[mainCharacterController selectedObjects] count]==0){
			NSLog(@"no characters selected processSpellsToCastTable");
			return;
		}
		obj=[[mainCharacterController selectedObjects] objectAtIndex:0];
	}else{
		obj=[self currentCharacter];
	}	
	int charLevel;
	NSManagedObject *characterClass;
	if(row<c1){
		charLevel=[[obj valueForKey:@"charClassLvl1"] intValue];
		characterClass=[obj valueForKey:@"characterClass1"];
	}else if(row<c1+c2){
		charLevel=[[obj valueForKey:@"charClassLvl2"] intValue];
		characterClass=[obj valueForKey:@"characterClass2"];
	}else{
		charLevel=[[obj valueForKey:@"charClassLvl3"] intValue];
		characterClass=[obj valueForKey:@"characterClass3"];
	}
	if([[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type==2 AND active==1"]] count]==0){
		[metaMagicEditButton setEnabled:NO];
	}else{
		if([[characterClass valueForKey:@"allSpontaneous"] boolValue]){
			[metaMagicEditButton setEnabled:YES];
		}else{
			[metaMagicEditButton setEnabled:NO];
			if([[characterClass valueForKey:@"healOrHarmSpontaneous"] boolValue]){
				if([[obj valueForKey:@"turnUndead"] boolValue] || [AbilityChanged isGood:obj]){
					if([[spell valueForKey:@"type"] intValue]==0){
						[metaMagicEditButton setEnabled:YES];
					}
				}else{
					if([[spell valueForKey:@"type"] intValue]==1){
						[metaMagicEditButton setEnabled:YES];
					}
				}
			}
			if([[characterClass valueForKey:@"summoningSpontaneous"] boolValue]){
				if([[spell valueForKey:@"type"] intValue]==3){
					[metaMagicEditButton setEnabled:YES];
				}
			}
		}
	}
	NSMutableString *range=[[NSMutableString alloc] initWithCapacity:5];
	if([[spell valueForKey:@"range"] isEqualToString:@"Personal"] || [[spell valueForKey:@"range"] isEqualToString:@"Touch"]){
		[range appendString:[spell valueForKey:@"range"]];
	}else{
		[range appendString:[SpellMethods processSpell:spell
											 withFeats:feats
												forKey:@"ran"
											  forLevel:charLevel]];
		if([[spell valueForKey:@"ranMeasuredIn"] intValue]==0){
			[range appendString:@" ft"];
		}else{
			[range appendString:@" miles"];
		}
	}
	[rangeTF setStringValue:@""];
	[rangeTF setStringValue:range];
	if([[spell valueForKey:@"type"] intValue]==0){
		[damageLabel setStringValue:@"Healing"];
	}else{
		[damageLabel setStringValue:@"Damage"];		
	}
	[damageTF setStringValue:@""];
	[damageTF setStringValue:[SpellMethods processSpell:spell
											  withFeats:feats
												 forKey:@"dam"
											   forLevel:charLevel]];
	[noaTF setStringValue:@""];
	if([[spell valueForKey:@"areaOfEffectOn"] boolValue]){
		[noaTF setStringValue:@"Inf."];
	}else{
		[noaTF setStringValue:[SpellMethods	processSpell:spell
											   withFeats:feats
												  forKey:@"noa"
												forLevel:charLevel]];		
	}
	NSMutableString *duration=[[NSMutableString alloc] initWithCapacity:5];
	[duration appendString:[SpellMethods processSpell:spell
											withFeats:feats
											   forKey:@"dur"
											 forLevel:charLevel]];
	//add concentration time to duration.
	if([[spell valueForKey:@"durForConc"] boolValue] && ![duration isEqualToString:@"None"]){
		[duration appendString:@"+conc"];
	}
	if([duration isEqualToString:@"None"]){
		if([[spell valueForKey:@"durForConc"] boolValue]){
			[duration setString:@"conc"];
		}else if([[spell valueForKey:@"durPermanent"] boolValue]){
			[duration setString:@"Permanent"];
		}else{
			[duration setString:@"Instant"];
		}
	}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==0){
		[duration appendString:@" rds"];
	}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==1){
		[duration appendString:@" mins"];
	}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==2){
		[duration appendString:@" hrs"];
	}else if([[spell valueForKey:@"durMeasuredIn"] intValue]==3){
		[duration appendString:@" days"];
	}
	[durationTF setStringValue:@""];
	[durationTF setStringValue:duration];
	[duration release];
	//casting time.
	NSString *casting;
	if([[spell valueForKey:@"castingTime"] intValue]==0){
		casting=@"Free";
	}else if([[spell valueForKey:@"castingTime"] intValue]==1){
		casting=@"Std";
	}else if([[spell valueForKey:@"castingTime"] intValue]==2){
		casting=@"1 rd";
	}else if([[spell valueForKey:@"castingTime"] intValue]==3){
		casting=[NSString stringWithFormat:@"%d rds",[[spell valueForKey:@"castingTimeCustom"] intValue]];
		//casting=@"";
	}
	[castingTF setStringValue:@""];
	[castingTF setStringValue:casting];
	if([[spell valueForKey:@"areaOfEffectOn"] boolValue]){
		if([[spell valueForKey:@"areaOfEffect"] intValue]==0){
			[aoeType setStringValue:@"Circle"];
			[aoeSizeLabel setStringValue:@"Radius"];
		}else{
			[aoeSizeLabel setStringValue:@"Length"];
			if([[spell valueForKey:@"areaOfEffect"] intValue]==1){
				[aoeType setStringValue:@"Cone"];
			}else{
				[aoeType setStringValue:@"Line"];
			}
		}
		[aoeSize setStringValue:[NSString stringWithFormat:@"%dft",[[spell valueForKey:@"areaOfEffectSize"] intValue]]];
	}else{
		[aoeSizeLabel setStringValue:@"Length"];
		[aoeSize setStringValue:@"N/A"];
		[aoeType setStringValue:@"None"];
	}
	//check feats for verbal.
	int i;
	BOOL silentSpell=NO;
	for(i=0;i<[feats count];i++){
		if([[[feats objectAtIndex:i] valueForKey:@"spellKey"] isEqualToString:@"Cast Silently"]){
			silentSpell=YES;
			break;
		}
	}
	if(silentSpell){
		[verbal setState:NSOffState];
	}else{
		[verbal setState:[[spell valueForKey:@"verbal"] intValue]];
	}
	BOOL stillSpell=NO;
	for(i=0;i<[feats count];i++){
		if([[[feats objectAtIndex:i] valueForKey:@"spellKey"] isEqualToString:@"Cast Still"]){
			stillSpell=YES;
			break;
		}
	}
	if(stillSpell){
			[somatic setState:NSOffState];
	}else{
		[somatic setState:[[spell valueForKey:@"somatic"] intValue]];
	}
	[material setState:[[spell valueForKey:@"material"] intValue]];
	[focus setState:[[spell valueForKey:@"focus"] intValue]];
	[xp setState:[[spell valueForKey:@"xp"] intValue]];
	[attackRoll setState:[[spell valueForKey:@"attackRoll"] intValue]];
	[dischargable setState:[[spell valueForKey:@"durDischarge"] intValue]];
	NSString *str=[spell valueForKey:@"materialCustom"];
	if(str==nil){
		[materialTF setStringValue:@""];
	}else{
		[materialTF setStringValue:str];
	}
	//check whethether can concentrate.
	if([[spell valueForKey:@"durForConc"] boolValue]){
		[toConcentrate setEnabled:YES];
		[toConcentrate setState:1];
	}else{
		[toConcentrate setEnabled:NO];
		[toConcentrate setState:0];
	}
	/*NSRange ran=[spellDescription selectedRange];
	[spellDescription selectAll:self];
	[spellDescription replaceCharactersInRange:[spellDescription selectedRange]
									  withRTFD:[spell valueForKey:@"theDescription"]];
	[spellDescription setSelectedRange:ran];*/
	NSString *str2=[spell valueForKey:@"theDescription2"];
	if(str2==nil){
		[spellDescription setString:@""];
	}else{
		[spellDescription setString:str2];
	}
	//setup 
	//setup feats.
	if([feats count]>0){
		int i;
		NSMutableString *strF=[[NSMutableString alloc] initWithCapacity:1];
		for(i=0;i<[feats count];i++){
			if(i==0){
				[strF appendString:[[feats objectAtIndex:i] valueForKey:@"name"]];
			}else{
				[strF appendFormat:@", %@",[[feats objectAtIndex:i] valueForKey:@"name"]];
			}
		}
		[metaFeatNamesBox setStringValue:strF];
		[strF release];
		//now apply any effects.
	}else{
		[metaFeatNamesBox setStringValue:@"No feats"];
	}
}
#pragma mark -
#pragma mark Attacking
#pragma mark
-(NSString *)deathCheck:(NSManagedObject *)obj{
	[characterController rearrangeObjects];
	NSString *message=@"";
	NSArray *feats=[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"active==1 AND type==3 AND miscUse==\"Conscious for Negative HP\" AND ability==0"]];
	if([[obj valueForKey:@"currentHP"] intValue]<=0 && !([feats count]>0)){
		if([[obj valueForKey:@"summoned"] boolValue]){
			//process character for exit.
			//need to display the message from this somehow.
			message=[NSString stringWithFormat:@"%@ has %d hit points as %@ is summoned %@ disappears.",[obj valueForKey:@"name"],[[obj valueForKey:@"currentHP"] intValue],[AbilityChanged getGenderOfCharacter:obj],[AbilityChanged getGenderOfCharacter:obj]];
			message=[self processForExitTheCharacter:obj
										 withMessage:message];
			[obj setValue:[NSNumber numberWithBool:NO]
				   forKey:@"mainPartyMember"];
			[obj setValue:[NSNumber numberWithBool:NO]
				   forKey:@"enemyPartyMember"];
			if([[obj valueForKey:@"temp"] boolValue]){
				NSManagedObject *cChar=[self currentCharacter];
				[characterController removeObject:obj];
				[mObjC deleteObject:obj];
				[characterController rearrangeObjects];
				if(![[self currentCharacter] isEqualTo:cChar]){
					[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]-1)]
								   forKey:@"currentCharacter"];
				}
			}
			return message;		
			//if dead remove from combat.
		}else if([[obj valueForKey:@"currentHP"] intValue]<-10){
			//check not immune to death.
			NSArray *imms=[[obj valueForKey:@"immunity"] allObjects];
			int i;
			for(i=0;i<[imms count];i++){
				if([[[imms objectAtIndex:i] valueForKey:@"damageType"] isEqualToString:@"Death"]){
					//possibly display a dialog.
					return nil;
				}
			}
			//if not then kill.
			//display this message.
			message=[NSString stringWithFormat:@"%@ has %d hit points and %@ is dead",[obj valueForKey:@"name"],[[obj valueForKey:@"currentHP"] intValue],[AbilityChanged getGenderOfCharacter:obj]];
			message=[self processForExitTheCharacter:obj
										 withMessage:message];
			[obj setValue:[NSNumber numberWithBool:NO]
					forKey:@"mainPartyMember"];
			[obj setValue:[NSNumber numberWithBool:NO]
					forKey:@"enemyPartyMember"];
			if([[obj valueForKey:@"temp"] boolValue]){
				NSManagedObject *cChar=[self currentCharacter];
				[mObjC deleteObject:obj];
				[characterController rearrangeObjects];
				if(![[self currentCharacter] isEqualTo:cChar]){
					[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]-1)]
								   forKey:@"currentCharacter"];
				}
			}
			return message;
		}else{//character just dying.
			[obj setValue:[NSNumber numberWithInt:0]
				   forKey:@"attacksLeftThisRound"];
			[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
						   forKey:@"currentCharacter"];
			return [NSString stringWithFormat:@"%@ has %d hit points and %@ is dying.",[obj valueForKey:@"name"],[[obj valueForKey:@"currentHP"] intValue],[AbilityChanged getGenderOfCharacter:obj]];
		}
	}
	return nil;
}
-(void)runAttackFromMainScreenByCharacter:(NSManagedObject *)obj{
	if([[characterController arrangedObjects] count]==0){
		NSLog(@"no characters");
		[characterController addObjects:[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"character"  substitutionVariables:[NSDictionary dictionary]] error:nil]];
	}
	NSManagedObject *ce=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentAttack"]
								 insertIntoManagedObjectContext:mObjC];
	[ce setValue:obj
		  forKey:@"caster"];
	[ce setValue:[obj valueForKey:@"defaultWeapon"]
		  forKey:@"weapon"];
	[ce setValue:[NSNumber numberWithInt:0]
		  forKey:@"attackAdj"];
	[characterController setSortDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]]];
	[self getTargetsForCurrentAttack:ce];
}
-(void)runAttackActions:(BOOL)moveAndAttack
		   forCharacter:(NSManagedObject *)obj{
	notFullAttack=0;
	if([[obj valueForKey:@"slowed"] boolValue] || moveAndAttack){
		notFullAttack=1;
	}else if([[obj valueForKey:@"usesWeapons"] boolValue] && !([[obj valueForKey:@"attacksLeftThisRound"] intValue]==[[obj valueForKey:@"noOfAttacks"] intValue])){
		notFullAttack=2;//for cancel screen so that the program knows just to add one attack left in this case.
	}
	if([[obj valueForKey:@"usesWeapons"] boolValue]){
		NSManagedObject *weap=[obj valueForKey:@"defaultWeapon"];
		int i;
		int noOfSimAttacks=[[weap valueForKey:@"noOfSimultaneousAttacks"] intValue];
		if(notFullAttack){
			noOfSimAttacks=1;
		}else{
			if([[obj valueForKey:@"usesTwoWeapons"] boolValue]){
				//do off hand weapon attack.
				NSManagedObject *offWeap=[obj valueForKey:@"offWeapon"];
				NSManagedObject *ce=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentAttack"]
											 insertIntoManagedObjectContext:mObjC];
				[ce setValue:obj
					  forKey:@"caster"];
				[ce setValue:offWeap
					  forKey:@"weapon"];
				[ce setValue:[NSNumber numberWithInt:0]
					  forKey:@"attackAdj"];				
			}
		}
		for(i=0;i<noOfSimAttacks;i++){
			//get the attack adjustment.
			int attackAdj=0;
			if([[obj valueForKey:@"noOfAttacks"] intValue]>[[obj valueForKey:@"attacksLeftThisRound"] intValue]){
				attackAdj=([[obj valueForKey:@"noOfAttacks"] intValue]-[[obj valueForKey:@"attacksLeftThisRound"] intValue])*-5;
			}
			NSManagedObject *ce=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentAttack"]
										 insertIntoManagedObjectContext:mObjC];
			[ce setValue:obj
				  forKey:@"caster"];
			[ce setValue:weap
				  forKey:@"weapon"];
			[ce setValue:[NSNumber numberWithInt:attackAdj]
				  forKey:@"attackAdj"];
		}
	}else{
		NSArray *array=[[obj valueForKey:@"weapons"] allObjects];
		if([array count]==0){
			[self setupBattleDisplayWithMessage:[NSString stringWithFormat:@"Error, %@ has no weapons so cannot attack.",[obj valueForKey:@"name"]]];
			return;
		}
		NSManagedObject *defWeap=[obj valueForKey:@"defaultWeapon"];
		int i;
		if(notFullAttack){
			array=[NSArray arrayWithObject:defWeap];
		}
		for(i=0;i<[array count];i++){
			int j;
			NSManagedObject *weap=[array objectAtIndex:i];
			int noOfSimAttacks=[[weap valueForKey:@"noOfSimultaneousAttacks"] intValue];
			if(notFullAttack){
				noOfSimAttacks=1;
			}
			for(j=0;j<noOfSimAttacks;j++){
				//get the attack adjustment.
				int attackAdj=-5;
				//primary weapon.
				if([weap isEqualTo:defWeap]){
					attackAdj=0;
				}
				NSManagedObject *ca=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentAttack"]
											 insertIntoManagedObjectContext:mObjC];
				[ca setValue:obj
					  forKey:@"caster"];
				[ca setValue:weap
					  forKey:@"weapon"];
				[ca setValue:[NSNumber numberWithInt:attackAdj]
					  forKey:@"attackAdj"];
			}			
		}
	}
	//slowed attack.
	if([[obj valueForKey:@"slowed"] boolValue] || moveAndAttack){
		[obj setValue:[NSNumber numberWithInt:0]
			   forKey:@"attacksLeftThisRound"];
	}else{
		[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"attacksLeftThisRound"] intValue]-1]
			   forKey:@"attacksLeftThisRound"];
	}
	attackSheetToDisplayCancel=YES;
}
-(BOOL)usingARangedAttackByChar:(NSManagedObject *)obj
				 mainAttackOnly:(BOOL)moa{
	//check if uses weapons or is only using a main attack.
	if([[obj valueForKey:@"usesWeapons"] boolValue] || moa){
		if([[[obj valueForKey:@"defaultWeapon"] valueForKey:@"weaponType"] intValue]==2){
			return YES;
		}
		return NO;
	}else{
		//if not using weapons and using all weapons.
		NSArray *weapons=[[obj valueForKey:@"weapons"] allObjects];
		int i;
		for(i=0;i<[weapons count];i++){//if any of them are ranged return YES.
			if([[[weapons objectAtIndex:i] valueForKey:@"weaponType"] intValue]==2){
				return YES;
			}
		}
	}
	return NO;
}
-(IBAction)refreshAttackTargetsTable:(id)sender{
	//NSLog(@"refreshing attack table");
	NSString *pred=[[characterController filterPredicate] predicateFormat];
	NSRange ran=[pred rangeOfString:@"id != "];
	ran.location=ran.location+6;
	ran.length=2;
	int theId=[[pred substringWithRange:ran] intValue];
	/*[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id==%d",theId]]];
	NSManagedObject *obj=[[characterController arrangedObjects] objectAtIndex:0];
	NSLog(@"obj.name=%@",[obj valueForKey:@"name"]);*/
	NSMutableString *thePredicate=[NSMutableString stringWithCapacity:15];
	if([mainScreen isVisible]){
		[thePredicate appendFormat:@"id != %d AND template==0",theId];
	}else{
		if([pred rangeOfString:@"mainPartyMember"].location==NSNotFound){
			[thePredicate appendFormat:@"id != %d AND enemyPartyMember==1",theId];
		}else{
			if([pred rangeOfString:@"enemyPartyMember"].location==NSNotFound){
				[thePredicate appendFormat:@"id != %d AND mainPartyMember==1",theId];
			}else{
				[thePredicate appendFormat:@"id != %d AND (mainPartyMember==1 OR enemyPartyMember==1)",theId];
			}
		}
	}
	if(![[NSUserDefaults standardUserDefaults] boolForKey:@"showInactive"]){
		[thePredicate appendString:@" AND paralysed==0 AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")"];
	}
	//NSLog(@"thePredicate=%@, pred=%@",thePredicate,pred);
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:thePredicate]];
	[attackTargetTable reloadData];
}
-(void)setupAttackOOforAction:(NSString *)action{
	NSManagedObject *obj=[self currentCharacter];
	[attackOOBlurb setStringValue:[NSString stringWithFormat:@"Has %@ caused any attacks of opportunity by %@? Please select any characters who get one or press 'No Attacks' if %@ doesn't suffer any.",[obj valueForKey:@"name"],action,[AbilityChanged getGenderOfCharacter:obj]]];
	if([[obj valueForKey:@"mainPartyMember"] boolValue] && [[obj valueForKey:@"enemyPartyMember"] boolValue]){
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id != %@ AND attackOOLeftThisRound>0 AND (mainPartyMember==1 OR enemyPartyMember==1)  AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")",[obj valueForKey:@"id"]]]];
	}else if([[obj valueForKey:@"mainPartyMember"] boolValue]){
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id != %@ AND attackOOLeftThisRound>0 AND enemyPartyMember==1 AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")",[obj valueForKey:@"id"]]]];
	}else{
		[characterController setFilterPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id != %@ AND attackOOLeftThisRound>0 AND mainPartyMember==1  AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")",[obj valueForKey:@"id"]]]];
	}
	[attackOOTable reloadData];
	[NSApp beginSheet:attackOOSheet
	   modalForWindow:battleScreen
		modalDelegate:self
	   didEndSelector:nil
		  contextInfo:NULL]; 
}
-(IBAction)attackOOSheetCancelled:(id)sender{
	[NSApp endSheet:attackOOSheet];
	[attackOOSheet orderOut:sender];
	[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
				   forKey:@"currentCharacter"];
	[self setupBattleDisplayWithMessage:nil];
}
-(IBAction)attackOOSheetEnded:(id)sender{
	[NSApp endSheet:attackOOSheet];
	[attackOOSheet orderOut:sender];
	NSArray *array=[[NSArray alloc] initWithArray:[[characterController arrangedObjects] objectsAtIndexes:[attackOOTable selectedRowIndexes]]];
	NSManagedObject *obj=[self currentCharacter];
	NSString *message=@"";
	int i;
	for(i=0;i<[array count];i++){
		NSManagedObject *obj2=[array objectAtIndex:i];
		[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"attackOOLeftThisRound"] intValue]-1]
				forKey:@"attackOOLeftThisRound"];
		//run an attack by the chosen character with their default weapon on the current character.
		NSManagedObject *ce=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentAttack"]
									 insertIntoManagedObjectContext:mObjC];
		[ce setValue:obj
			  forKey:@"target"];
		[ce setValue:obj2
			  forKey:@"caster"];
		[ce setValue:[obj valueForKey:@"defaultWeapon"]
			  forKey:@"weapon"];
		[ce setValue:[NSNumber numberWithInt:0]
			  forKey:@"attackAdj"];
		if([message isEqualToString:@""]){
			message=[self runAttackForCurrentAttack:ce];
		}else{
			message=[NSString stringWithFormat:@"%@\n%@",message,[self runAttackForCurrentAttack:ce]];
		}
	}
	[array release];
	NSString *message2=[self deathCheck:obj];
	if(message2!=nil){
		if([message isEqualToString:@""]){
			message=message2;
		}else{
			[message stringByAppendingFormat:@"\n%@",message2];
		}
	}	
	[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]+1)]
				   forKey:@"currentCharacter"];
	[self setupBattleDisplayWithMessage:message];
}
-(IBAction)changeCover:(id)sender{
	if([coverButton state]==1){
		if([improvedCoverButton state]==1){
			[acAdjTF setIntValue:[acAdjTF intValue]+8];
		}else{
			[acAdjTF setIntValue:[acAdjTF intValue]+4];
		}
		[improvedCoverButton setEnabled:YES];
	}else{
		if([improvedCoverButton state]==1){
			[acAdjTF setIntValue:[acAdjTF intValue]-8];
		}else{
			[acAdjTF setIntValue:[acAdjTF intValue]-4];
		}
		[improvedCoverButton setEnabled:NO];
	}
}
-(IBAction)changeImprovedCover:(id)sender{
	if([improvedCoverButton state]==1){
		[acAdjTF setIntValue:[acAdjTF intValue]+4];
	}else{
		[acAdjTF setIntValue:[acAdjTF intValue]-4];
	}
}
-(IBAction)changeFlanked:(id)sender{
	if([flankedButton state]==1){
		[attackAdjTF setIntValue:[attackAdjTF intValue]+2];
	}else{
		[attackAdjTF setIntValue:[attackAdjTF intValue]-2];
	}
}
-(IBAction)checkRangeIsOK:(id)sender{
	NSString *maxRange=[maxRangeBlurb stringValue];
	NSRange range;
	range.location=35;
	range.length=[maxRange length]-41;
	if([distanceToEnemyTF intValue]>[[maxRange substringWithRange:range] intValue]){
		[attackContinueButton setEnabled:NO];
	}else{
		[attackContinueButton setEnabled:YES];
	}
}
-(void)getTargetsForCurrentAttack:(NSManagedObject *)currentAttack{
	NSManagedObject *obj=[currentAttack valueForKey:@"caster"];
	NSManagedObject *weap=[currentAttack valueForKey:@"weapon"];
	//choose a target
	NSMutableString *thePredicate=[NSMutableString stringWithCapacity:15];
	if([mainScreen isVisible]){
		[thePredicate appendFormat:@"id != %d AND template==0",[[obj valueForKey:@"id"] intValue]];
	}else{
		if([[obj valueForKey:@"mainPartyMember"] boolValue] && [[obj valueForKey:@"enemyPartyMember"] boolValue]){
			
		}else if([[obj valueForKey:@"mainPartyMember"] boolValue]){
			[thePredicate appendFormat:@"id != %@  AND enemyPartyMember==1",[obj valueForKey:@"id"]];
		}else{
			[thePredicate appendFormat:@"id != %@ AND mainPartyMember==1",[obj valueForKey:@"id"]];
		}
	}
	//check button
	if(![[NSUserDefaults standardUserDefaults] boolForKey:@"showInactive"]){
		[thePredicate appendString:@"AND paralysed==0 AND (currentHP>0 OR ANY feats.miscUse==\"Conscious for Negative HP\")"];
	}
	[characterController setFilterPredicate:[NSPredicate predicateWithFormat:thePredicate]];
	//blurb.
	[attackBlurb setStringValue:[NSString stringWithFormat:@"%@ is attacking using a %@, who do you wish to attack?",[obj valueForKey:@"name"],[weap valueForKey:@"name"]]];
	//set up buttons and niling attack adjustments.
	[flankedButton setState:0];
	[coverButton setState:0];
	[improvedCoverButton setState:0];
	[attackAdjTF setIntValue:0];
	[acAdjTF setIntValue:0];
	NSSize size;
	size.width=440;
		//check if ranged/thrown weapon.
	if([[weap valueForKey:@"weaponType"] intValue]==0){
		[distanceToEnemyLabel setHidden:YES];
		[distanceToEnemyTF setHidden:YES];
		[rangeIncrementLabel setHidden:YES];
		[rangeIncrementTF setHidden:YES];
		[maxRangeBlurb setHidden:YES];
		[flankedButton setEnabled:YES];
		size.height=460;
	}else{
		[distanceToEnemyLabel setHidden:NO];
		[distanceToEnemyTF setHidden:NO];
		[rangeIncrementLabel setHidden:NO];
		[rangeIncrementTF setHidden:NO];
		[flankedButton setEnabled:NO];
		[rangeIncrementTF setStringValue:[NSString stringWithFormat:@"%@ft",[weap valueForKey:@"rangeIncrement"]]];
		[maxRangeBlurb setStringValue:[NSString stringWithFormat:@"The maximum range of this weapon is %d feet.",[[weap valueForKey:@"maxRange"] intValue]]];
		[maxRangeBlurb setHidden:NO];
		size.height=478;
	}
	[attackSheet setContentSize:size];
	NSWindow *displayScreen;
	if([mainScreen isVisible]){
		displayScreen=mainScreen;
	}else{
		displayScreen=battleScreen;
	}
	[attackTargetTable reloadData];
	//setup below properties.
	if([attackTargetTable selectedRow]>-1 && [[characterController arrangedObjects] count]>0){
		if([[[[characterController arrangedObjects] objectAtIndex:[attackTargetTable selectedRow]] valueForKey:@"paralysed"] boolValue]){
			[attackAdjTF setIntValue:5];
		}
	}
	//check whether cancelable.
	if(attackSheetToDisplayCancel){
		[attackCancelButton setTitle:@"Cancel"];
	}else{
		[attackCancelButton setTitle:@"Skip Attack"];
	}
	[NSApp beginSheet:attackSheet
	   modalForWindow:displayScreen
		modalDelegate:self
	   didEndSelector:@selector(targetForAttackChosen:returnCode:currentAttack:)
		  contextInfo:currentAttack]; 
}
-(IBAction)attackWindowClosed:(id)sender{
	[attackSheet orderOut:sender];
	[NSApp endSheet:attackSheet returnCode:0];
}
-(IBAction)attackWindowCanceled:(id)sender{
	[attackSheet orderOut:sender];
	[NSApp endSheet:attackSheet returnCode:-1];
}
-(void)targetForAttackChosen:(NSWindow *)panel
						returnCode:(int)returnCode
					 currentAttack:(NSManagedObject *)currentAttack{
	if(returnCode==-1){
		if(attackSheetToDisplayCancel){//check if cancelling as that removes one from the character count.
			[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]-1)]
						   forKey:@"currentCharacter"];
			NSManagedObject *obj=[currentAttack valueForKey:@"caster"];
			[battleStore setValue:[obj valueForKey:@"initiative"]
						   forKey:@"currentInitiative"];
			if(notFullAttack==1){
				[obj setValue:[obj valueForKey:@"noOfAttacks"]
					   forKey:@"attacksLeftThisRound"];
			}else{
				[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"attacksLeftThisRound"] intValue]+1]
					   forKey:@"attacksLeftThisRound"];
			}
		}
		[mObjC deleteObject:currentAttack];
		if([mainScreen isVisible]){
			[characterController setFilterPredicate:nil];
		}
		//don't want to display cancel no more.
		attackSheetToDisplayCancel=NO;
		[self setupBattleDisplayWithMessage:nil];
		return;
	}
	//don't want to display cancel no more.
	attackSheetToDisplayCancel=NO;
	[currentAttack setValue:[[characterController arrangedObjects] objectAtIndex:[attackTargetTable selectedRow]]
					 forKey:@"target"];
	//check range increment.
	int rangeInc=[[[currentAttack valueForKey:@"weapon"] valueForKey:@"rangeIncrement"] intValue];
	int rangePenalty;
	if(rangeInc==0){
		rangePenalty=0;
	}else{
		rangePenalty=-2*([distanceToEnemyTF intValue]/rangeInc);
	}
	//set the attack adj to include range increment and the attack adj chosen on the screen.
	[currentAttack setValue:[NSNumber numberWithInt:[distanceToEnemyTF intValue]]
					 forKey:@"range"];
	[currentAttack setValue:[NSNumber numberWithInt:[attackAdjTF intValue]-[acAdjTF intValue]+[[currentAttack valueForKey:@"attackAdj"] intValue]+rangePenalty]
					 forKey:@"attackAdj"];
	NSString *message=[self runAttackForCurrentAttack:currentAttack];
	if([mainScreen isVisible]){
		[characterController setFilterPredicate:nil];
	}
	[self setupBattleDisplayWithMessage:message];
}
-(NSString *)runAttackForCurrentAttack:(NSManagedObject *)currentAttack{
	NSString *message=@"";
	//more stuff.
	NSManagedObject *obj=[currentAttack valueForKey:@"caster"];
	NSManagedObject *obj2=[currentAttack valueForKey:@"target"];
	NSManagedObject *weap=[currentAttack valueForKey:@"weapon"];
	int attackAdj=[[currentAttack valueForKey:@"attackAdj"] intValue];
	int range=[[currentAttack valueForKey:@"range"] intValue];
	//enable required feats.
	[FeatActions setupFeatsForCaster:obj
						   forTarget:obj2
							   atRange:range
							   nowOn:YES];
	//apply character vs target feats to the characters.
	//roll dices.
	int diceRoll=[RandomNumbers randomIntUpTo:20];
	int bonus=attackAdj+[[weap valueForKey:@"attackBonus"] intValue];
	//get targets AC.
	int targetAC;
	if([[obj2 valueForKey:@"flatFooted"] boolValue]){
		targetAC=[[obj2 valueForKey:@"armourClassFlat"] intValue];
	}else{
		targetAC=[[obj2 valueForKey:@"armourClassTotal"] intValue];
	}	
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
		NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d for %@'s attack on %@ (a %d or a roll of 20 required to hit, a roll of 1 is always a miss).",diceRoll,bonus,[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],targetAC];
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
					   forKey:@"eventLog"];
	}
	//check status.
	if(diceRoll==1){
		//failure
		message=[NSString stringWithFormat:@"%@ has  tried to attack %@ and has critically missed.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
		
	}else if(diceRoll==20){
		//success.
		message=[self processDamageWithCurrentAttack:currentAttack
							   withCriticalHit:[self aCriticalHitMadeForDieRoll:20
																	  forWeapon:weap
																   forAttackAdj:attackAdj
																	OnCharacter:obj2]
								 withAttackAdj:attackAdj];
	}else{
		//check attack
		if(diceRoll+bonus>=targetAC){
			//we have hit.
			message=[self processDamageWithCurrentAttack:currentAttack
										 withCriticalHit:[self aCriticalHitMadeForDieRoll:diceRoll
																		  forWeapon:weap
																	   forAttackAdj:attackAdj
																		OnCharacter:obj2]
										   withAttackAdj:attackAdj];
		}else{
			//we have missed.
			message=[NSString stringWithFormat:@"%@ has tried to attack %@ and has missed.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
		}
	}
	[currentAttack setValue:[NSNumber numberWithBool:YES]
					 forKey:@"processed"];
	//disable required feats.
	[FeatActions setupFeatsForCaster:obj
						   forTarget:obj2
							 atRange:range
							   nowOn:NO];
	//now attach the message to the current event.
	[currentAttack setValue:message
					 forKey:@"resultMessage"];
	return nil;
}
-(NSString *)processDamageWithCurrentAttack:(NSManagedObject *)currentAttack
					  withCriticalHit:(BOOL)ch
						withAttackAdj:(int)attackAdj{
	NSManagedObject *obj=[currentAttack valueForKey:@"caster"];
	NSManagedObject *obj2=[currentAttack valueForKey:@"target"];
	NSManagedObject *weap=[currentAttack valueForKey:@"weapon"];
	int diceDamage=0;
	int i;
	for(i=0;i<[[weap valueForKey:@"noOfDamageDie"] intValue];i++){
		diceDamage=diceDamage+[RandomNumbers randomIntUpTo:[[weap valueForKey:@"sizeOfDamageDie"] intValue]];
	}
	//add fixed bonus.
	int bonusDamage=[[weap valueForKey:@"fixedBonusDamage"] intValue];
	//add strength bonus too.
	bonusDamage=bonusDamage+[AbilityChanged strengthWeaponBonus:weap];
	//check for critical hit.
	if(ch){
		bonusDamage=bonusDamage*[[weap valueForKey:@"criticalMultiplier"] intValue];
		diceDamage=diceDamage*[[weap valueForKey:@"criticalMultiplier"] intValue];
	}
	[currentAttack setValue:[NSNumber numberWithInt:diceDamage]
					 forKey:@"diceDamage"];
	[currentAttack setValue:[NSNumber numberWithInt:bonusDamage]
					 forKey:@"bonusDamage"];
	int damage=diceDamage+bonusDamage;
	//check for immunities.
	damage=[self checkForImmunityOnCharacter:obj2
							  withDamageType:[weap valueForKey:@"damageType"]
							  withWeaponPlus:[[weap valueForKey:@"magicalWeapon"] intValue]
								  withDamage:damage];
	if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
		NSString *newMessage;
		if(ch){
			newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d for %@'s damage on %@, the critical hit bonus is included.",diceDamage,bonusDamage,[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
		}else{
			newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d for %@'s damage on %@.",diceDamage,damage-diceDamage,[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
		}
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
					   forKey:@"eventLog"];
	}
	int damageBonusDice=0;
	if([[weap valueForKey:@"bonusDieDamage"] boolValue]){
		//now do bonus damage.
		for(i=0;i<[[weap valueForKey:@"noOfBonusDamageDie"] intValue];i++){
			damageBonusDice=damageBonusDice+[RandomNumbers randomIntUpTo:[[weap valueForKey:@"sizeOfBonusDamageDie"] intValue]];
		}
		[currentAttack setValue:[NSNumber numberWithInt:damageBonusDice]
						 forKey:@"bonusDieDamage"];
		damageBonusDice=[self checkForImmunityOnCharacter:obj2
										   withDamageType:[weap valueForKey:@"bonusDamageType"]
										   withWeaponPlus:-1
											   withDamage:damageBonusDice];
		if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
			NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d for %@'s bonus damage dice on %@.",damageBonusDice,[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
			[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
						   forKey:@"eventLog"];
		}
	}
	damage=damage+damageBonusDice;
	[currentAttack setValue:[NSNumber numberWithInt:damage]
					 forKey:@"totalDamage"];
	int currentHP=[[obj2 valueForKey:@"currentHP"] intValue];
	//commit damage
	[obj2 setValue:[NSNumber numberWithInt:currentHP-damage]
			forKey:@"currentHP"];
	NSString *message;
	if(ch){
		message=[NSString stringWithFormat:@"%@ has had a critical hit on %@ doing %d damage, taking %@ to %d hit points.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
	}else{
		message=[NSString stringWithFormat:@"%@ has hit %@ doing %d damage, taking %@ to %d hit points.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
	}
	//create a current damage object.
	if(damage>0){
		NSManagedObject *cd=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentDamage"]
									 insertIntoManagedObjectContext:mObjC];
		[cd setValue:obj
			  forKey:@"caster"];
		[cd setValue:obj2
			  forKey:@"target"];
		[cd setValue:[NSNumber numberWithInt:damage]
			  forKey:@"damage"];
	}
	//check character has HP left (for cleave).
	if(currentHP>0 && currentHP-damage<=0){
		//unconcious/dead
		NSString *message2=[self deathCheck:obj2];
		if(message2!=nil){
			if([message isEqualToString:@""]){
				message=message2;
			}else{
				[message stringByAppendingFormat:@"\n%@",message2];
			}
		}
		//give XP to killing characters party.
		/*if([[obj valueForKey:@"mainPartyMember"] boolValue] && [[obj2 valueForKey:@"enemyPartyMember"] boolValue]){
			//party 1 gets XP
			[self grantXPToParty:1
					 forTargetCR:[[obj2 valueForKey:@"challengeRating"] doubleValue]];
		}else if([[obj valueForKey:@"enemyPartyMember"] boolValue] && [[obj2 valueForKey:@"mainPartyMember"] boolValue]){
			//party 2 gets XP
			[self grantXPToParty:2
					 forTargetCR:[[obj2 valueForKey:@"challengeRating"] doubleValue]];
		}*/
		//check the level of the monster.
		NSArray *feats=[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"active==1 AND type==3 AND miscUse BEGINSWITH \"Extra Attack when Enemy Killed\" AND ability==0"]];
		//NSLog(@"number of cleave feats=%d",[feats count]);
		if([feats count]>0){
			NSManagedObject *theFeat=[feats objectAtIndex:0];
			if(![[obj valueForKey:@"cleaveUsedThisRound"] boolValue] || [[theFeat valueForKey:@"miscUse"] isEqualToString:@"Extra Attack when Enemy Killed (Unlimited)"]){
				[obj setValue:[NSNumber numberWithBool:YES]
					   forKey:@"cleaveUsedThisRound"];
				//run an extra attack
				NSManagedObject *ce=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"CurrentAttack"]
											 insertIntoManagedObjectContext:mObjC];
				[ce setValue:obj
					  forKey:@"caster"];
				[ce setValue:weap
					  forKey:@"weapon"];
				[ce setValue:[NSNumber numberWithInt:attackAdj]
					  forKey:@"attackAdj"];
			}
		}
	}
	return message;
}
-(int)checkForImmunityOnCharacter:(NSManagedObject *)target
				   withDamageType:(NSString *)damageType
				   withWeaponPlus:(int)plus
					   withDamage:(int)damage{
	//NSLog(@"initial damage=%d",damage);
	//check if damage vs. undead if not undead return zero (weapons, only spells use a new and improved system.
	if([damageType isEqualTo:@"vs Undead"] && ![[target valueForKey:@"type"] isEqualToString:@"Undead"]){
		return 0;
	}
	//get all immunities.
	NSArray *imms=[[target valueForKey:@"immunity"] allObjects];
	int i;
	for(i=0;i<[imms count];i++){
		NSManagedObject *immunity=[imms objectAtIndex:i];
		//check if a weapon plus effect.
		if([[immunity valueForKey:@"damageType"] hasSuffix:@"Weapon"]){
			NSRange range;
			range.location=2;
			range.length=1;
			int plusImm=[[[immunity valueForKey:@"damageType"] substringWithRange:range] intValue];
			//plus is -1 if it's not a weapon.
			if(plusImm>plus && plus!=-1){
				//resistant to magic weapons.
				int immLeft=[[immunity valueForKey:@"value"] intValue];
				if(damage<immLeft){
					damage=0;
				}else{
					damage=damage-immLeft;
				}
			}
		}else{
			//other type of immunity.
			if([[immunity valueForKey:@"damageType"] isEqualToString:damageType]){
				//check if vulnerability or resistance.
				if([[immunity valueForKey:@"vulnerability"] boolValue]){
					//assume %age.
					damage=damage+(int)((double)damage*[[immunity valueForKey:@"value"] doubleValue]/100.0+0.5);
				}else{
					//check if percentage or normal.
					if([[immunity valueForKey:@"percentage"] boolValue]){
						damage=damage-(int)((double)damage*[[immunity valueForKey:@"value"] doubleValue]/100.0+0.5);
						if(damage<0){
							damage=0;
						}
					}else{
						int immLeft=[[immunity valueForKey:@"value"] intValue];
						if(damage<immLeft){
							damage=0;
						}else{
							damage=damage-immLeft;
						}	
					}					
				}
			}
		}
		if(damage==0){
			return 0;
		}else if(damage<0){
			NSLog(@"immunities not working correctly.");
			return 0;
		}
	}
	return damage;
}
-(BOOL)aCriticalHitMadeForDieRoll:(int)dieRoll
						forWeapon:(NSManagedObject *)weap
					 forAttackAdj:(int)adj
					  OnCharacter:(NSManagedObject *)obj2{
	if(dieRoll>=[[weap valueForKey:@"minRollForCritical"] intValue]){
		//check immunity to criticals.
		int i;
		NSArray *array=[[[obj2 valueForKey:@"immunity"] allObjects] valueForKey:@"name"];
		for(i=0;i<[array count];i++){
			if([[array objectAtIndex:i] hasPrefix:@"Critical Hits"]){
				return NO;
			}
		}
		//get targets AC.
		int targetAC;
		if([[obj2 valueForKey:@"flatFooted"] boolValue]){
			targetAC=[[obj2 valueForKey:@"armourClassFlat"] intValue];
		}else{
			targetAC=[[obj2 valueForKey:@"armourClassTotal"] intValue];
		}
		//check whether crit roll made.
		int roll2=[RandomNumbers randomIntUpTo:20];
		int bonus=adj+[[weap valueForKey:@"attackBonus"] intValue];
		if([[NSUserDefaults standardUserDefaults] boolForKey:@"logDiceRolls"]){
			NSString *newMessage=[NSString stringWithFormat:@"\nRolled a %d+%d for to check for a critical hit against %@ (%d required, a dice roll of 20 succeeds and a 1 fails).",roll2,bonus,[obj2 valueForKey:@"name"],targetAC];
			[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",newMessage]
						   forKey:@"eventLog"];
		}
		if(roll2==20 || (roll2+bonus>targetAC && roll2 !=1)){
			return YES;
		}
	}
	return NO;
}
#pragma mark -
#pragma mark Random
#pragma mark
//spell discharge.
-(IBAction)cancelSpellDischargeSheet:(id)sender{
	[spellDischargeSheet orderOut:sender];
	[NSApp endSheet:spellDischargeSheet];
}
-(IBAction)processSpellDischargeSheet:(id)sender{
	[spellDischargeSheet orderOut:sender];
	[NSApp endSheet:spellDischargeSheet];
	NSIndexSet *is=[spellDischargeTable selectedRowIndexes];
	//as in table.
	NSManagedObject *obj=[self currentCharacter];
	NSArray *array=[[obj valueForKey:@"casterOfActiveEvent"] allObjects];
	int i;
	int count=0;
	NSMutableArray *spellArray=[[NSMutableArray alloc] initWithCapacity:5];
	for(i=0;i<[array count];i++){
		NSManagedObject *event=[array objectAtIndex:i];
		if(![[event entity] isEqualTo:[[model entitiesByName]  objectForKey:@"ActiveSpell"]]){
			continue;
		}
		count++;
		if([[[event valueForKey:@"spell"] valueForKey:@"durDischarge"] boolValue]){
			[spellArray addObject:event];
		}
	}
	NSString *message=@"";
	NSArray *eventsToGo=[spellArray objectsAtIndexes:is];
	for(i=0;i<[eventsToGo count];i++){
		count--;
		message=[self killTheActiveEvent:[eventsToGo objectAtIndex:i]
						   withCharacter:obj
							 withMessage:message
								  toExit:NO];
	}
	if(count==0){
		[spellDischargeM setEnabled:NO];
		[spellDischargeE setEnabled:NO];
	}else{
		[spellDischargeM setEnabled:YES];
		[spellDischargeE setEnabled:YES];
	}
	[self setupBattleDisplayWithMessage:message];
}

-(IBAction)startNextRound:(id)sender{
	[mainTabs selectTabViewItemAtIndex:1];
	[currentlyBusy startAnimation:self];
	[self beginningOfRoundSetup];
}
#pragma mark - 
#pragma mark Delegate methods
#pragma mark
-(void)controlTextDidChange:(NSNotification *)aNotification{
	if([[aNotification object] isEqualTo:customInitToWaitFor]){
		int currentInit=[[battleStore valueForKey:@"currentInitiative"] intValue];
		int valueInBox=[customInitToWaitFor intValue];
		if(valueInBox>currentInit){
			[customWaitButton setEnabled:NO];
		}else{
			[customWaitButton setEnabled:YES];
		}
	}
}
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification{
	if([[aNotification object] isEqualTo:turnUndeadTable]){
		//NSLog(@"turn undead table");
		NSArray *array=[[characterController arrangedObjects] objectsAtIndexes:[turnUndeadTable selectedRowIndexes]];//gets currently selected characters.
		int i;
		int currentDamage=0;//adds up their HD or Level.
		for(i=0;i<[array count];i++){
			if([[array objectAtIndex:i] valueForKey:@"noOfHD"]==nil){
				currentDamage=currentDamage+[[[array objectAtIndex:i] valueForKey:@"level"] intValue];
			}else{
				currentDamage=currentDamage+[[[array objectAtIndex:i] valueForKey:@"noOfHD"] intValue];	
			}
		}
		int damageLeft=[turnUndeadDamageTotal intValue]-currentDamage;
		[turnUndeadDamageLeft setIntValue:damageLeft];
		if(damageLeft<0){
			[turnUndeadCloseButton setEnabled:NO];
		}else{
			[turnUndeadCloseButton setEnabled:YES];
		}
	}else if([[aNotification object] isEqualTo:waitTable]){
		//NSLog(@"wait table");
		[self processWaitButtons];
	}else if([[aNotification object] isEqualTo:spellsToCastTable]){
		[self processSpellsToCastTable];
	}else if([[aNotification object] isEqualTo:featChangeTable]){
		if([featChangeTable selectedRow]==-1){
			return;
		}
		if([[featsController selectedObjects] count]==0){
			NSLog(@"nothing selected in featController for feat Change table");
			return;
		}
		NSManagedObject *feat=[[featsController selectedObjects] objectAtIndex:0];
		if([FeatActions xValueInUse:feat]){
			[xModTF setEnabled:YES];
			[xModTF setIntValue:[[feat valueForKey:@"xValue"] intValue]];
			[xModTF setBackgroundColor:[NSColor colorWithDeviceRed:1.0
															 green:1.0
															  blue:1.0
															 alpha:1.0]];
		}else{
			[xModTF setEnabled:NO];
			[xModTF setStringValue:@"N/A"];
			[xModTF setBackgroundColor:[NSColor colorWithDeviceRed:0.93
															 green:0.93
															  blue:0.93
															 alpha:1.0]];
		}
	}else if([[aNotification object] isEqualTo:spellTargetsChooserTable]){
		if([[characterController selectedObjects] count]==0){
			return;
		}
		//check if character already has a target.
		if([aoeInvisibox intValue]==1 && [[[[[characterController arrangedObjects] objectAtIndex:[spellTargetsChooserTable selectedRow]] valueForKey:@"targetOfSpell"] allObjects] count]>0){
			[addToSpellTargetsButton setEnabled:NO];
		}else{
			[addToSpellTargetsButton setEnabled:YES];
			if([spellTargetTable numberOfRows]>=[noOfAttacksTF intValue] && [noOfAttacksTF intValue]!=0){
				[addToSpellTargetsButton setEnabled:NO];				
			}else{
				[addToSpellTargetsButton setEnabled:YES];
			}
		}
	}else if([[aNotification object] isEqualTo:spellTargetTableEdit]){
		//refresh the buttons on the right.
		if([[spellTargetController selectedObjects] count]==0){
			NSLog(@"Error, in SelectionDidChange, no spell target in spellTargetTableEdit selected.");
			return;
		}		
		NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
		NSManagedObject *obj2=[st valueForKey:@"character"];
		int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
		if([fixedBonusDamageEdit2 isEnabled]){
			[diceDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
			[fixedBonusDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
			[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];
		}else{
			[diceDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																	  green:0.93
																	   blue:0.93
																	  alpha:1.0]];
			[fixedBonusDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																			green:0.93
																			 blue:0.93
																			alpha:1.0]];
			[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];
		}
	}else if([[aNotification object] isEqualTo:toChooseSurprisedCharsTable]){
		if([[characterController selectedObjects] count]==0){
			return;
		}
		NSManagedObject *obj=[[characterController selectedObjects] objectAtIndex:0];
		if([[obj valueForKey:@"surprised"] boolValue]){
			[addToSurprisedButton setEnabled:NO];
		}else{
			[addToSurprisedButton setEnabled:YES];
		}
	}else if([[aNotification object] isEqualTo:attackTargetTable]){
		if([[characterController arrangedObjects] count]==0 || [attackTargetTable selectedRow]==-1){
			return;
		}
		NSManagedObject *obj=[[characterController arrangedObjects] objectAtIndex:[attackTargetTable selectedRow]];
		if(lastCharParalysed){
			[attackAdjTF setIntValue:[attackAdjTF intValue]-5];
		}
		if([[obj valueForKey:@"paralysed"] boolValue]){
			[attackAdjTF setIntValue:[attackAdjTF intValue]+5];
			lastCharParalysed=YES;
		}else{
			lastCharParalysed=NO;
		}
		if([rangeIncrementTF isHidden]){
			if([[[[obj valueForKey:@"feats"] allObjects] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"miscUse like[c] \"Immune to being Flanked in Combat\""]] count]>0){
				if([flankedButton isEnabled] && [flankedButton state]==1){
					[attackAdjTF setIntValue:[attackAdjTF intValue]-2];
				}
				[flankedButton setEnabled:NO];
			}else{
				if(![flankedButton isEnabled] && [flankedButton state]==1){
					[attackAdjTF setIntValue:[attackAdjTF intValue]+2];
				}
				[flankedButton setEnabled:YES];
			}
		}
	}
}
- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(int)rowIndex{
	if([aTableView isEqualTo:spellTargetTableEdit]){
		if([fixedBonusDamageEdit2 isEnabled] || [targetFailedSaveEdit isEnabled] || [attackRollEdit isEnabled] || [spellResistanceEdit isEnabled]){
			return YES;
		}else{
			return NO;
		}
	}
	return YES;
}
- (void)tabView:(NSTabView *)tabView
didSelectTabViewItem:(NSTabViewItem *)tabViewItem{
	//NSLog(@"tab view selection changed.");
	if([tabView isEqualTo:optionTabs]){
		[self processOptionTabsForTabViewItem:tabViewItem];
	}else if([tabView isEqualTo:mainTabs]){
		if([tabViewItem isEqualTo:[[mainTabs tabViewItems] objectAtIndex:0]]){
			[self processOptionTabsForTabViewItem:[optionTabs selectedTabViewItem]];
		}else if([tabViewItem isEqualTo:[[mainTabs tabViewItems] objectAtIndex:1]]){
		}else if([tabViewItem isEqualTo:[[mainTabs tabViewItems] objectAtIndex:2]]){
			[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];
			/*NSTabViewItem *oldView=[infoViewInEOR selectedTabViewItem];
			NSTabViewItem *newView=[[NSTabViewItem alloc] init];
			[newView setLabel:[oldView label]];
			[infoViewInEOR insertTabViewItem:newView atIndex:0];
			[newView setView:infoView];
			[infoViewInEOR removeTabViewItem:oldView];*/
			//[[infoViewInEOR selectedTabViewItem] setView:infoView];
			NSRect rect=[battleScreen frame];
			if([moreDetailButton2 state]==NSOffState){
				rect.origin.y=rect.origin.y+(rect.size.height-380);
				rect.size.height=380;
			}else{
				rect.origin.y=rect.origin.y+(rect.size.height-602);
				rect.size.height=602;
			}
			[battleScreen setFrame:rect display:YES];
		}
	}
}
- (void)windowWillClose:(NSNotification *)aNotification{
	if([[aNotification object] isEqualTo:battleScreen]){
		[self editCharactersCode];
	}
}
#pragma mark -
#pragma mark More random
#pragma mark
-(NSString *)processForExitTheCharacter:(NSManagedObject *)obj
							withMessage:(NSString *)message{
	//NSLog(@"processing character %@ for exit.",[obj valueForKey:@"name"]);
	[obj setValue:[obj valueForKey:@"noOfAttacks"]
		   forKey:@"attacksLeftThisRound"];
	[obj setValue:[obj valueForKey:@"maxAttackOO"]
		   forKey:@"attackOOLeftThisRound"];
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"flatFooted"];
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"healthCheckedThisRound"];
	[obj setValue:nil
		   forKey:@"initiative"];
	[obj setValue:[NSNumber numberWithBool:NO]
		   forKey:@"surprised"];
	if([[obj valueForKey:@"charged"] boolValue]){
		[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"meleeMiscBonus"] intValue]-2]
			   forKey:@"meleeMiscBonus"];
		[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassTotal"] intValue]+2]
			   forKey:@"armourClassTotal"];
		[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassFlat"] intValue]+2]
			   forKey:@"armourClassFlat"];
		[obj setValue:[NSNumber numberWithInt:[[obj valueForKey:@"armourClassTouch"] intValue]+2]
			   forKey:@"armourClassTouch"];
		[obj setValue:[NSNumber numberWithBool:NO]
			   forKey:@"charge"];
	}
	//remove all active events.
	message=[self processActiveEventsForTheMessage:message
								   forTheCharacter:obj];
	//nil feat targets.
	NSArray *feats=[[obj valueForKey:@"feats"] allObjects];
	int i;
	for(i=0;i<[feats count];i++){
		[[feats objectAtIndex:i] setValue:nil
								   forKey:@"target"];
	}
	return message;
}
-(NSString *)processActiveEventsForTheMessage:(NSString *)message
							forTheCharacter:(NSManagedObject *)obj{
	NSArray *array = [[obj valueForKey:@"casterOfActiveEvent"] allObjects];
	int i;
	for(i=0;i<[array count];i++){
		NSManagedObject *activeEvent=[array objectAtIndex:i];
		//kill the event.
		message=[self killTheActiveEvent:activeEvent
						   withCharacter:obj
							 withMessage:message
								  toExit:YES];
	}
	return message;
}
-(NSString *)killTheActiveEvent:(NSManagedObject *)event
				  withCharacter:(NSManagedObject *)obj
					withMessage:(NSString *)message2
						 toExit:(BOOL)toExit{
	//NSLog(@"killing an active event.");
	NSString *eventBlurb;
	//check type as message different for each
	if([[event entity] isEqualTo:[NSEntityDescription entityForName:@"ActiveSpell" inManagedObjectContext:mObjC]]){
		NSManagedObject *spell=[event valueForKey:@"spell"];
		if([[spell valueForKey:@"paralysesTargets"] boolValue]){
			NSArray *targets=[[event valueForKey:@"target"] allObjects];
			int i;
			for(i=0;i<[targets count];i++){
				NSManagedObject *obj2=[targets objectAtIndex:i];
				[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"paralysed"] intValue]-1]
						forKey:@"paralysed"];
			}
		}
		if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			NSArray *targets=[[event valueForKey:@"target"] allObjects];
			int i;
			for(i=0;i<[targets count];i++){
				NSManagedObject *obj2=[targets objectAtIndex:i];
				[FeatActions processFeat:spell
								forKeyNo:1
								  onChar:obj2
								forwards:NO];
				[FeatActions processFeat:spell
								forKeyNo:2
								  onChar:obj2
								forwards:NO];
				[FeatActions processFeat:spell
								forKeyNo:3
								  onChar:obj2
								forwards:NO];
				[FeatActions processFeat:spell
								forKeyNo:4
								  onChar:obj2
								forwards:NO];
			}
		}else if([[spell valueForKey:@"type"] intValue]==3){
			//then summoning so remove character from battle.
			int i;
			NSArray *targets=[[event valueForKey:@"target"] allObjects];
			for(i=0;i<[targets count];i++){
				NSManagedObject *obj2=[targets objectAtIndex:i];
				//actually dead.
				[obj2 setValue:[NSNumber numberWithBool:NO]
					   forKey:@"mainPartyMember"];
				[obj2 setValue:[NSNumber numberWithBool:NO]
					   forKey:@"enemyPartyMember"];
				//check obj initiative compared to current.
				[characterController setFilterPredicate:[NSPredicate predicateWithFormat:@"mainPartyMember == 1 OR enemyPartyMember == 1"]];//reset display.
				//getting the current character.
				if([[obj2 valueForKey:@"temp"] boolValue]){
					[mObjC deleteObject:obj2];
				}
				[characterController rearrangeObjects];
				[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"numberOfActiveChars"] intValue]-1)]
							   forKey:@"numberOfActiveChars"];
				//checking if obj2 is still the current character.
				if(![obj isEqualTo:[[characterController arrangedObjects] objectAtIndex:[[battleStore valueForKey:@"currentCharacter"] intValue]]]){
					[battleStore setValue:[NSNumber numberWithInt:([[battleStore valueForKey:@"currentCharacter"] intValue]-1)]
								   forKey:@"currentCharacter"];
				}
			}
		}
		[event setValue:nil
				 forKey:@"target"];
		eventBlurb=[NSString stringWithFormat:@"The Spell %@ cast by %@ has finished.",[[event valueForKey:@"spell"] valueForKey:@"name"],[obj valueForKey:@"name"]];
	}else if([[event entity] isEqualTo:[NSEntityDescription entityForName:@"ActiveTurning" inManagedObjectContext:mObjC]]){
		if([[event valueForKey:@"turnUndead"] boolValue]){
			int j;
			NSArray *targets=[[event valueForKey:@"target"] allObjects];
			for(j=0;j<[targets count];j++){
				[[targets objectAtIndex:j] setValue:[NSNumber numberWithBool:NO]
											 forKey:@"turned"];
			}
		}else{//rebuked.
			  //reverse AC changes.
			NSArray *targets=[[event valueForKey:@"target"] allObjects];
			int j;
			for(j=0;j<[targets count];j++){
				NSManagedObject *obj2=[targets objectAtIndex:j];
				[obj2 setValue:[NSNumber numberWithBool:NO]
					   forKey:@"turned"];
				[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassDeflection"] intValue]+2)]
					   forKey:@"armourClassDeflection"];
				[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassFlat"] intValue]+2)]
					   forKey:@"armourClassFlat"];
				[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassTouch"] intValue]+2)]
					   forKey:@"armourClassTouch"];
				[obj2 setValue:[NSNumber numberWithInt:([[obj valueForKey:@"armourClassTotal"] intValue]+2)]
					   forKey:@"armourClassTotal"];
			}
		}		
		eventBlurb=[NSString stringWithFormat:@"%@'s use of Turn Undead has finished.",[obj valueForKey:@"name"]];
	}else if([[event entity] isEqualTo:[NSEntityDescription entityForName:@"ActiveFeat" inManagedObjectContext:mObjC]]){
		//NSLog(@"removing feat/ability");
		 NSManagedObject *feat=[event valueForKey:@"feat"];
		 if([FeatActions inCombatFeatShouldActivate:feat]){
			 [FeatActions activateInCodeTheFeat:feat
								  nowShouldBeOn:NO];
		 }
		//check whether a new feat is now activated (not on exit)
		 NSString *featOrAbility;
		 if([[feat valueForKey:@"ability"] boolValue]){
			 featOrAbility=@"special ability";
		 }else{
			 featOrAbility=@"feat";
		 }
		if([[feat valueForKey:@"causesAfterEffects"] boolValue] && [feat valueForKey:@"afterEffects"]!=nil && !toExit){
			//NSLog(@"after effects");
			NSManagedObject *feat2=[feat valueForKey:@"afterEffects"];
			//NSLog(@"after effects feat name=%@",[feat2 valueForKey:@"name"]);
			if([FeatActions inCombatFeatShouldActivate:feat2]){
				[FeatActions activateInCodeTheFeat:feat2
									 nowShouldBeOn:YES];
			}
			if(![[feat2 valueForKey:@"lastsForever"] boolValue]){
				NSManagedObject *activeFeat=[[NSManagedObject alloc] initWithEntity:[[model entitiesByName]  objectForKey:@"ActiveFeat"]
													 insertIntoManagedObjectContext:mObjC];
				if([[feat2 valueForKey:@"runsUntilBattleEnded"] boolValue]){
					[activeFeat setValue:[NSNumber numberWithInt:0]
								  forKey:@"lastsUntilRound"];
				}else{
					[activeFeat setValue:[NSNumber numberWithInt:[[feat2 valueForKey:@"timeLastsFor"] intValue]+1]
								  forKey:@"lastsUntilRound"];
				}
				[activeFeat setValue:obj
							  forKey:@"caster"];
				[activeFeat setValue:feat2
							  forKey:@"feat"];
			}
			eventBlurb=[NSString stringWithFormat:@"%@'s %@ %@ has finished, the ability %@ has now been activated.",[obj valueForKey:@"name"],featOrAbility,[feat valueForKey:@"name"],[feat2 valueForKey:@"name"]];
		}else{
			eventBlurb=[NSString stringWithFormat:@"%@'s %@ %@ has finished.",[obj valueForKey:@"name"],featOrAbility,[feat valueForKey:@"name"]];
		}
	}
	//NSLog(@"eventBlurb=%@",eventBlurb);
	//set the message up, with a new line for each entry.
	if([message2 isEqualToString:@""]){
		message2=eventBlurb;
	}else{
		message2=[NSString stringWithFormat:@"%@\n%@",message2,eventBlurb];
	}
	[mObjC deleteObject:event];
	return message2;
}
#pragma mark -
#pragma mark Table Stuff
#pragma mark
-(int)numberOfRowsInTableView:(NSTableView *)aTableView{
	//NSLog(@"battle noOfRows");
	if([aTableView isEqualTo:turnUndeadTable]){
		return [[characterController arrangedObjects] count];
	}else if([aTableView isEqualTo:spellsToCastTable]){
		//NSLog(@"charactersSpellClasses.count=%d",[charactersSpellClasses count]);
		return [charactersSpellClasses count];
	}else if([aTableView isEqualTo:attackOOTable]){
		return [[characterController arrangedObjects] count];
	}else if([aTableView isEqualTo:featTargetTable]){
		return [[characterController arrangedObjects] count];
	}else if([aTableView isEqualTo:spellTargetTable]){
		return [[spellTargetController arrangedObjects] count];
	}else if([aTableView isEqualTo:spellDischargeTable]){
		NSManagedObject *obj=[self currentCharacter];
		NSArray *array=[[obj valueForKey:@"casterOfActiveEvent"] allObjects];
		int i;
		int count=0;
		for(i=0;i<[array count];i++){
			NSManagedObject *event=[array objectAtIndex:i];
			if(![[event entity] isEqualTo:[[model entitiesByName]  objectForKey:@"ActiveSpell"]]){
				continue;
			}
			if([[[event valueForKey:@"spell"] valueForKey:@"durDischarge"] boolValue]){
				count++;
			}
		}
		return count;
	}else if([aTableView isEqualTo:spellOverwriteTable]){
		return [charactersSpellClasses count];
	}else if([aTableView isEqualTo:attackTargetTable]){
		return [[characterController arrangedObjects] count];
	}else if([aTableView isEqualTo:spellTargetsChooserTable]){
		//NSLog(@"cc size=%d",[[characterController arrangedObjects] count]);
		return [[characterController arrangedObjects] count];
	}else if([aTableView isEqualTo:surprisedCharactersTable]){
		//NSLog(@"hi, count=%d",[surprisedCharactersList count]);
		return [surprisedCharactersList count];
	}else if([aTableView isEqualTo:testAttributeTable]){
		return [[skillController arrangedObjects] count]+9;
	}
	return 0;
}
-(id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
		   row:(int)row{
	//NSLog(@"table objectvalueFor...");
	//NSLog(@"object setup for table view.");
	if([aTableView isEqualTo:turnUndeadTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:1]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"currentHP"];
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:2]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"maxHP"];
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:3]]){
			NSManagedObject *obj=[[characterController arrangedObjects] objectAtIndex:row];
			if([obj valueForKey:@"noOfHD"]==nil){
				return [obj valueForKey:@"level"];
			}
			return [obj valueForKey:@"noOfHD"];
		}
	}else if([aTableView isEqualTo:spellsToCastTable]){
		NSManagedObject *tempSpellClass=[charactersSpellClasses objectAtIndex:row];
		NSManagedObject *spellClass=[tempSpellClass valueForKey:@"spellClass"];
		NSString *thingToSend;
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			if([tempSpellClass valueForKey:@"castAtLevelTemp"]==nil){
				thingToSend=[NSString stringWithFormat:@"%d",[[spellClass valueForKey:@"level"] intValue]];
			}else{
				thingToSend=[NSString stringWithFormat:@"%d (%d)",[[spellClass valueForKey:@"level"] intValue],[[tempSpellClass valueForKey:@"castAtLevelTemp"] intValue]];		
			}
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:1]]){
			thingToSend=[[spellClass valueForKey:@"spell"] valueForKey:@"name"];
		}else{
			int noLeft=[[tempSpellClass valueForKey:@"noOfSpellsLeftTemp"] intValue];
			if(noLeft==0){
				thingToSend=@">0";
			}else{
				thingToSend=[NSString stringWithFormat:@"%d",noLeft];
			}
		}
		if([[spellClass valueForKey:@"domainSpell"] boolValue]){
			return [[NSAttributedString alloc] initWithString:thingToSend attributes:[NSDictionary dictionaryWithObject:[NSColor colorWithDeviceRed:0.7 green:0.1 blue:0.0 alpha:1.0] forKey:NSForegroundColorAttributeName]];
		}else{
			return [[NSAttributedString alloc] initWithString:thingToSend attributes:[NSDictionary dictionaryWithObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName]];	
		}
	}else if([aTableView isEqualTo:attackOOTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
		}else{
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"attackOOLeftThisRound"];
		}
	}else if([aTableView isEqualTo:featTargetTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			return [tyn transformedValue:[[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"mainPartyMember"]];
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:1]]){
			return [tyn transformedValue:[[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"enemyPartyMember"]];
		}else{
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
		}
	}else if([aTableView isEqualTo:spellTargetTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			return [[[spellTargetController arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
		}
	}else if([aTableView isEqualTo:spellDischargeTable]){
		NSManagedObject *obj=[self currentCharacter];
		NSArray *array=[[obj valueForKey:@"casterOfActiveEvent"] allObjects];
		int i;
		NSMutableArray *spellArray=[[NSMutableArray alloc] initWithCapacity:5];
		for(i=0;i<[array count];i++){
			NSManagedObject *event=[array objectAtIndex:i];
			if(![[event entity] isEqualTo:[[model entitiesByName]  objectForKey:@"ActiveSpell"]]){
				continue;
			}
			if([[[event valueForKey:@"spell"] valueForKey:@"durDischarge"] boolValue]){
				[spellArray addObject:event];
			}
		}
		return [[[spellArray objectAtIndex:row] valueForKey:@"spell"] valueForKey:@"name"];
	}else if([aTableView isEqualTo:spellOverwriteTable]){
		NSManagedObject *obj;
		if([mainScreen isVisible]){
			if([[mainCharacterController selectedObjects] count]==0){
				return nil;
			}
			obj=[[mainCharacterController selectedObjects] objectAtIndex:0];
		}else{
			obj=[self currentCharacter];
		}
		
		if(charactersSpellClasses==nil || [charactersSpellClasses count]==0 || obj==nil){
			NSLog(@"failed to setup overwrite table");
			return nil;
		}
		NSString *thingToSend;
		NSManagedObject *tempSpellClass=[charactersSpellClasses objectAtIndex:row];
		NSManagedObject *spellClass=[tempSpellClass valueForKey:@"spellClass"];
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			if([tempSpellClass valueForKey:@"castAtLevelTemp"]==nil){
				thingToSend=[NSString stringWithFormat:@"%d",[[spellClass valueForKey:@"level"] intValue]];
			}else{
				thingToSend=[NSString stringWithFormat:@"%d (%d)",[[spellClass valueForKey:@"level"] intValue],[[tempSpellClass valueForKey:@"castAtLevelTemp"] intValue]];		
			}
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:1]]){
			thingToSend=[[spellClass valueForKey:@"spell"] valueForKey:@"name"];
		}else{			
			thingToSend=[NSString stringWithFormat:@"%d",[[tempSpellClass valueForKey:@"noOfSpellsLeftTemp"] intValue]];
		}
		if([[spellClass valueForKey:@"domainSpell"] boolValue]){
			return [[NSAttributedString alloc] initWithString:thingToSend attributes:[NSDictionary dictionaryWithObject:[NSColor colorWithDeviceRed:0.7 green:0.1 blue:0.0 alpha:1.0] forKey:NSForegroundColorAttributeName]];
		}else{
			return [[NSAttributedString alloc] initWithString:thingToSend attributes:[NSDictionary dictionaryWithObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName]];	
		}
	}else if([aTableView isEqualTo:attackTargetTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			NSString *str=[[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
			//[[characterController arrangedObjects] release];
			return str;
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:1]]){
			NSNumber *num=[[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"currentHP"];
			//[[characterController arrangedObjects] release];
			return num;
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:2]]){
			NSNumber *num=[[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"maxHP"];
			//[[characterController arrangedObjects] release];
			return num;
		}else{
			NSNumber *num=[ac transformedValue:[[characterController arrangedObjects] objectAtIndex:row]];
			//[[characterController arrangedObjects] release];
			return num;
		}
	}else if([aTableView isEqualTo:spellTargetsChooserTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"name"];
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:1]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"currentHP"];
		}else if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:2]]){
			return [[[characterController arrangedObjects] objectAtIndex:row] valueForKey:@"maxHP"];
		}else{
			return [ac transformedValue:[[characterController arrangedObjects] objectAtIndex:row]];
			//return @"-3";
		}
	}else if([aTableView isEqualTo:surprisedCharactersTable]){
		//NSLog(@"obj to return");
		return [[surprisedCharactersList objectAtIndex:row] valueForKey:@"name"];
	}else if([aTableView isEqualTo:testAttributeTable]){
		if([aTableColumn isEqualTo:[[aTableView tableColumns] objectAtIndex:0]]){
			switch(row){
				case 0:
					return @"Strength";
				case 1:
					return @"Dexterity";
				case 2:
					return @"Constitution";
				case 3:
					return @"Intelligence";
				case 4:
					return @"Wisdom";
				case 5:
					return @"Charisma";
				case 6:
					return @"Fortitude Save";
				case 7:
					return @"Reflex Save";
				case 8:
					return @"Will Save";
				default:
					return [[[skillController arrangedObjects] objectAtIndex:row-9] valueForKey:@"name"];
			}
		}else{
			NSManagedObject *obj=[self currentCharacter];
			switch(row){
				case 0:
					return [NSNumber numberWithInt:[AbilityChanged scoreToBonus:[obj valueForKey:@"strength"]]];
				case 1:
					return [NSNumber numberWithInt:[AbilityChanged scoreToBonus:[obj valueForKey:@"dexterity"]]];
				case 2:
					return [NSNumber numberWithInt:[AbilityChanged scoreToBonus:[obj valueForKey:@"constitution"]]];
				case 3:
					return [NSNumber numberWithInt:[AbilityChanged scoreToBonus:[obj valueForKey:@"intelligence"]]];
				case 4:
					return [NSNumber numberWithInt:[AbilityChanged scoreToBonus:[obj valueForKey:@"wisdom"]]];
				case 5:
					return [NSNumber numberWithInt:[AbilityChanged scoreToBonus:[obj valueForKey:@"charisma"]]];
				case 6:
					return [obj valueForKey:@"fortitudeTotal"];
				case 7:
					return [obj valueForKey:@"reflexTotal"];
				case 8:
					return [obj valueForKey:@"willTotal"];
				default:
					return [[[skillController arrangedObjects] objectAtIndex:row-9] valueForKey:@"total"];
			}
		}
	}
	return nil;
}
#pragma mark -
#pragma mark Editing Attacks/Spells and message return
#pragma mark

-(void)alertFromCurrentEventDidEnd:(NSWindow *)sheet
			  returnCode:(int)code
			 contextInfo:(NSManagedObject *)currentEvent{
	if(code==NSAlertDefaultReturn){
		//log message.
		NSString *message=[currentEvent valueForKey:@"resultMessage"];
		[battleStore setValue:[[battleStore valueForKey:@"eventLog"] stringByAppendingFormat:@"\n%@",message]
					   forKey:@"eventLog"];
		//check type for currentSpell.
		[spellTargetTableEdit setDelegate:nil];
		if([[currentEvent entity] isEqualTo:[[model entitiesByName]  objectForKey:@"CurrentSpell"]]){
			NSArray *arrayTargets=[[currentEvent valueForKey:@"spellTarget"] allObjects];
			
			int i;
			for(i=0;i<[arrayTargets count];i++){
				NSManagedObject *st=[arrayTargets objectAtIndex:i];
				[spellTargetController removeObject:st];
				[mObjC deleteObject:st];
			}
		}
		[spellTargetTableEdit setDelegate:self];
		[mObjC deleteObject:currentEvent];
		[self setupBattleDisplayWithMessage:nil];
	}else{
		//NSLog(@"Editing event");
		NSString *message=[currentEvent valueForKey:@"resultMessage"];
		if([[currentEvent entity] isEqualTo:[[model entitiesByName]  objectForKey:@"CurrentSpell"]]){
			NSString *className=[currentEvent valueForKey:@"className"];
			NSManagedObject *obj=[currentEvent valueForKey:@"caster"];
			[arcaneSpellFailureEdit setState:1];
			if(([className isEqualToString:@"Sorcerer"] || [className isEqualToString:@"Wizard"] || [className isEqualToString:@"Bard"]) && [[obj valueForKey:@"arcaneSpellFailure"] intValue]>0){
				[arcaneSpellFailureEdit setEnabled:YES];
				if([message rangeOfString:@"arcane spell failure"].location!=NSNotFound){
					[arcaneSpellFailureEdit setState:0];
				}
			}else{
				[arcaneSpellFailureEdit setEnabled:NO];
			}
			if([message rangeOfString:@"failed a concentration check"].location!=NSNotFound){
				//display sheet 1.
				[concentrationCheckEdit setState:0];
			}else{
				[concentrationCheckEdit setState:1];
			}
			//set up controller.
			//[spellTargetController addObjects:[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"spellTarget" substitutionVariables:[NSDictionary dictionary]]
			//													   error:nil]];
			[spellTargetController setAutomaticallyPreparesContent:NO];
			[spellTargetController prepareContent];
			[spellTargetController setAutomaticallyPreparesContent:YES];
			//set up "new" values.
			NSArray *sTargets=[spellTargetController arrangedObjects];
			int i;
			for(i=0;i<[sTargets count];i++){
				NSManagedObject *spellTarget=[sTargets objectAtIndex:i];
				int bonus=[[spellTarget valueForKey:@"bonusDamage"] intValue];
				[spellTarget setValue:[NSNumber numberWithInt:bonus]
							   forKey:@"newBonusDamage"];
				int dice=[[spellTarget valueForKey:@"diceDamage"] intValue];
				[spellTarget setValue:[NSNumber numberWithInt:dice]
							   forKey:@"newDiceDamage"];
				int total=[[spellTarget valueForKey:@"totalDamage"] intValue];
				[spellTarget setValue:[NSNumber numberWithInt:total-dice-bonus]
							   forKey:@"newMiscBonus"];
				[spellTarget setValue:[NSNumber numberWithInt:total]
							   forKey:@"newTotalDamage"];
			}
			//check dice roll backgrounds.
			BOOL diceWhite=NO;
			if([[spellTargetController selectedObjects] count]>0){
				NSManagedObject *spellTarget=[[spellTargetController selectedObjects] objectAtIndex:0];
				//NSManagedObject *obj2=[spellTarget valueForKey:@"character"];
				//int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[spellTarget valueForKey:@"totalDamage"] intValue];
				if([[enableDRolls transformedValue:spellTarget] boolValue]){
					diceWhite=YES;
					//[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];
				}else{
					//[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];		
				}
			}
			if(diceWhite){
				if([[spellTargetController selectedObjects] count]==0){
					NSLog(@"Error in alertFromCurrentEventDidEnd.diceWhite, no spell targets selected");
				}else{
					NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
					NSManagedObject *obj2=[st valueForKey:@"character"];
					[diceDamageEdit2 setEnabled:YES];
					[fixedBonusDamageEdit2 setEnabled:YES];
					[totalDamageEdit2 setEnabled:YES];
					[miscBonusEdit2 setEnabled:YES];
					[diceDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
					[fixedBonusDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
					int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
					[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];					
				}
			}else{
				[diceDamageEdit2 setEnabled:NO];
				[fixedBonusDamageEdit2 setEnabled:NO];
				[totalDamageEdit2 setEnabled:NO];
				[miscBonusEdit2 setEnabled:NO];
				[diceDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																		  green:0.93
																		   blue:0.93
																		  alpha:1.0]];
				[fixedBonusDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																				green:0.93
																				 blue:0.93
																				alpha:1.0]];
				if([[spellTargetController selectedObjects] count]>0){
				   NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
				   NSManagedObject *obj2=[st valueForKey:@"character"];
				   int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
				   [targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];
				}else{
					[targetHPLeftEdit2 setStringValue:@""];
				}
			}
			if([mainScreen isVisible]){
				[NSApp beginSheet:editSheet2
				   modalForWindow:mainScreen
					modalDelegate:self
				   didEndSelector:@selector(editSheetDidEnd:returnCode:contextInfo:)
					  contextInfo:currentEvent];
			}else{
				[NSApp beginSheet:editSheet2
				   modalForWindow:battleScreen
					modalDelegate:self
				   didEndSelector:@selector(editSheetDidEnd:returnCode:contextInfo:)
					  contextInfo:currentEvent];
			}
		}else if([[currentEvent entity] isEqualTo:[[model entitiesByName]  objectForKey:@"CurrentAttack"]]){
			//check if target can accept criticals.
			NSManagedObject *obj2=[currentEvent valueForKey:@"target"];
			BOOL targetImmuneToCrits=NO;
			NSArray *array=[[[obj2 valueForKey:@"immunity"] allObjects] valueForKey:@"name"];
			int i;
			for(i=0;i<[array count];i++){
				if([[array objectAtIndex:i] hasPrefix:@"Critical Hits"]){
					targetImmuneToCrits=YES;
					break;
				}
			}
			if(targetImmuneToCrits){
				[canEnableCriticalEdit setIntValue:0];
			}else{
				[canEnableCriticalEdit setIntValue:1];
			}
			if([message hasSuffix:@"and has missed."] || [message hasSuffix:@"has critically missed."]){
				[criticalHitEdit setState:0];
				[criticalHitEdit setEnabled:NO];
				[hitTargetEdit setState:0];
				[self processDamageEditFieldsToEnable:NO];
				[bonusDiceDamageEdit setStringValue:@""];
				[miscBonusEdit setStringValue:@""];
				[fixedBonusDamageEdit setStringValue:@""];
				[diceDamageEdit setStringValue:@""];
				[totalDamageEdit setStringValue:@""];
			}else{
				if([canEnableCriticalEdit intValue]==0){
					[criticalHitEdit setEnabled:NO];
				}else{
					[criticalHitEdit setEnabled:YES];					
				}
				[hitTargetEdit setState:1];
				if([message rangeOfString:@"critical hit"].location!=NSNotFound){
					[criticalHitEdit setState:1];
				}else{
					[criticalHitEdit setState:0];
				}
				[self processDamageEditFieldsToEnable:YES];
				//apply damage.
				[diceDamageEdit setIntValue:[[currentEvent valueForKey:@"diceDamage"] intValue]];
				[fixedBonusDamageEdit setIntValue:[[currentEvent valueForKey:@"bonusDamage"] intValue]];
				if([[[currentEvent valueForKey:@"weapon"] valueForKey:@"bonusDieDamage"] boolValue]){
					[bonusDiceDamageEdit setEnabled:YES];
					[bonusDiceDamageEdit setBackgroundColor:[NSColor whiteColor]];
					[bonusDiceDamageEdit setIntValue:[[currentEvent valueForKey:@"bonusDiceDamage"] intValue]];
				}else{
					[bonusDiceDamageEdit setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																				  green:0.93
																				   blue:0.93
																				  alpha:1.0]];
					[bonusDiceDamageEdit setStringValue:@""];
					[bonusDiceDamageEdit setEnabled:NO];
				}
				int total=[diceDamageEdit intValue]+[fixedBonusDamageEdit intValue]+[bonusDiceDamageEdit intValue];
				[totalDamageEdit setIntValue:[[currentEvent valueForKey:@"totalDamage"] intValue]];
				[miscBonusEdit setIntValue:[totalDamageEdit intValue]-total];
			}
			[targetHPLeftEdit setStringValue:[NSString stringWithFormat:@"%@ now has %d hit points.",[obj2 valueForKey:@"name"],[[obj2 valueForKey:@"currentHP"] intValue]]];
			if([mainScreen isVisible]){
				[NSApp beginSheet:editSheet
				   modalForWindow:mainScreen
					modalDelegate:self
				   didEndSelector:@selector(editSheetDidEnd:returnCode:contextInfo:)
					  contextInfo:currentEvent];
			}else{
				[NSApp beginSheet:editSheet
				   modalForWindow:battleScreen
					modalDelegate:self
				   didEndSelector:@selector(editSheetDidEnd:returnCode:contextInfo:)
					  contextInfo:currentEvent];
			}
		}
	}
}
-(IBAction)hitTargetEditPressed:(id)sender{
	NSArray *eventsWithMessages=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"eventWithAMessage" substitutionVariables:[NSDictionary dictionary]]
													 error:nil];
	NSManagedObject *ce=[eventsWithMessages objectAtIndex:0];
	NSManagedObject *obj2=[ce valueForKey:@"target"];
	int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[ce valueForKey:@"totalDamage"] intValue];
	if([hitTargetEdit state]==1){
		[self processDamageEditFieldsToEnable:YES];
		if([canEnableCriticalEdit intValue]==0){
			[criticalHitEdit setEnabled:NO];
		}else{
			[criticalHitEdit setEnabled:YES];					
		}
		[targetHPLeftEdit setStringValue:[NSString stringWithFormat:@"%@ now has %d hit points.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit intValue]]];
	}else{
		[criticalHitEdit setEnabled:NO];
		[self processDamageEditFieldsToEnable:NO];
		[targetHPLeftEdit setStringValue:[NSString stringWithFormat:@"%@ now has %d hit points.",[obj2 valueForKey:@"name"],preAttackHP]];

	}
}
-(void)processDamageEditFieldsToEnable:(BOOL)toEnable{
	if(toEnable){
		[miscBonusEdit setEnabled:YES];
		[fixedBonusDamageEdit setEnabled:YES];
		[fixedBonusDamageEdit setBackgroundColor:[NSColor whiteColor]];
		[diceDamageEdit setEnabled:YES];
		[diceDamageEdit setBackgroundColor:[NSColor whiteColor]];
		[totalDamageEdit setEnabled:YES];		
	}else{
		[bonusDiceDamageEdit setEnabled:NO];
		[bonusDiceDamageEdit setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																	  green:0.93
																	   blue:0.93
																	  alpha:1.0]];
		[miscBonusEdit setEnabled:NO];
		[miscBonusEdit setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																green:0.93
																 blue:0.93
																alpha:1.0]];
		[fixedBonusDamageEdit setEnabled:NO];
		[fixedBonusDamageEdit setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																	   green:0.93
																		blue:0.93
																	   alpha:1.0]];
		[diceDamageEdit setEnabled:NO];
		[diceDamageEdit setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																 green:0.93
																  blue:0.93
																 alpha:1.0]];
		[totalDamageEdit setEnabled:NO];
	}
}
-(IBAction)criticalHitsChanged:(id)sender{
	NSArray *eventsWithMessages=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"eventWithAMessage" substitutionVariables:[NSDictionary dictionary]]
													 error:nil];
	NSManagedObject *ce=[eventsWithMessages objectAtIndex:0];
	NSManagedObject *weap=[ce valueForKey:@"weapon"];
	if([criticalHitEdit state]==1){
		[diceDamageEdit setIntValue:[diceDamageEdit intValue]*[[weap valueForKey:@"criticalMultiplier"] intValue]];
		[fixedBonusDamageEdit setIntValue:[fixedBonusDamageEdit intValue]*[[weap valueForKey:@"criticalMultiplier"] intValue]];
	}else{
		[diceDamageEdit setIntValue:[diceDamageEdit intValue]/[[weap valueForKey:@"criticalMultiplier"] intValue]];
		[fixedBonusDamageEdit setIntValue:(int)((double)[fixedBonusDamageEdit intValue]/(double)[[weap valueForKey:@"criticalMultiplier"] intValue]+0.5)];
	}
	[self addUpDamageEdit:self];
}
-(IBAction)addUpDamageEdit:(id)sender{
	NSArray *eventsWithMessages=[mObjC executeFetchRequest:[model fetchRequestFromTemplateWithName:@"eventWithAMessage" substitutionVariables:[NSDictionary dictionary]]
													 error:nil];
	NSManagedObject *ce=[eventsWithMessages objectAtIndex:0];
	int total1=[diceDamageEdit intValue]+[fixedBonusDamageEdit intValue];
	NSManagedObject *weap=[ce valueForKey:@"weapon"];
	NSManagedObject *obj2=[ce valueForKey:@"target"];
	int total2=[self checkForImmunityOnCharacter:obj2
								  withDamageType:[weap valueForKey:@"damageType"]
								  withWeaponPlus:[[weap valueForKey:@"magicalWeapon"] intValue]
									  withDamage:total1];
	int misc=total2-total1;
	if([bonusDiceDamageEdit isEnabled]){
		int totalB1=[bonusDiceDamageEdit intValue];
		int totalB2=[self checkForImmunityOnCharacter:obj2
									   withDamageType:[weap valueForKey:@"typeOfBonusDamage"]
									   withWeaponPlus:-1			
										   withDamage:totalB1];
		misc=misc+totalB2-totalB1;
		total2=total2+totalB2;
	}
	[miscBonusEdit setIntValue:misc];
	[totalDamageEdit setIntValue:total2];
	//now setup string.
	int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[ce valueForKey:@"totalDamage"] intValue];
	[targetHPLeftEdit setStringValue:[NSString stringWithFormat:@"%@ now has %d hit points.",[obj2 valueForKey:@"name"],preAttackHP-total2]];
}
-(IBAction)arcaneSpellFailurePressed:(id)sender{
	if([arcaneSpellFailureEdit state]==0){
		[concentrationCheckEdit setEnabled:NO];
	}else{
		[concentrationCheckEdit setEnabled:YES];		
	}
}
-(IBAction)concentrationCheckPressed:(id)sender{
	NSArray *array2=[spellTargetController arrangedObjects];
	if([array2 count]==0){
		NSLog(@"a problem, no spell targets.");
		return;
	}
	NSManagedObject *spell=[[[[array2 objectAtIndex:0] valueForKey:@"currentSpell"] valueForKey:@"spellClass"] valueForKey:@"spell"];
	if([concentrationCheckEdit state]==0){
		[spellTargetTableEdit setDelegate:nil];
		[spellTargetTableEdit deselectAll:nil];
		[spellTargetTableEdit setDelegate:self];
		[spellTargetTableEdit setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																	   green:0.93
																		blue:0.93
																	   alpha:1.0]];		
		[diceDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																  green:0.93
																   blue:0.93
																  alpha:1.0]];
		[fixedBonusDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																		green:0.93
																		 blue:0.93
																		alpha:1.0]];
		[targetHPLeftEdit2 setStringValue:@""];
		if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			int i;
			NSArray *array=[spellTargetController arrangedObjects];
			for(i=0;i<[array count];i++){
				//NSLog(@"disabling feat.");
				[[array objectAtIndex:i] setValue:[NSNumber numberWithBool:NO]
										   forKey:@"newFeatEnabled"];
			}
		}
	}else{
		if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			int i;
			NSArray *array=[spellTargetController arrangedObjects];
			for(i=0;i<[array count];i++){
				NSManagedObject *st=[array objectAtIndex:i];
				if([[enableDRolls transformedValue:st] boolValue]){
					//NSLog(@"enabling feat.");
					[st setValue:[NSNumber numberWithBool:NO]
						  forKey:@"newFeatEnabled"];
				}
			}
		}
		[spellTargetTableEdit selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
		[spellTargetTableEdit setBackgroundColor:[NSColor whiteColor]];
		[diceDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
		[fixedBonusDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
		//setting up label.
		//NSLog(@"more array woes");
		if([[spellTargetController selectedObjects] count]==0){
			NSLog(@"Error, in ConcentrationCheckPassed, no target selected");
			return;
		}
		NSManagedObject *spellTarget=[[spellTargetController selectedObjects] objectAtIndex:0];
		NSManagedObject *obj2=[spellTarget valueForKey:@"character"];
		int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[spellTarget valueForKey:@"totalDamage"] intValue];
		if([[enableDRolls transformedValue:spellTarget] boolValue]){
			[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];
		}else{
			[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];
		}
	}
}
-(IBAction)passedSpellResistancePressed:(id)sender{
	if([[spellTargetController selectedObjects] count]==0){
		NSLog(@"Error, in SpellResistancePressed, no target selected");
		return;
	}	
	NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
	NSManagedObject *obj2=[st valueForKey:@"character"];
	NSManagedObject *spell=[[[st valueForKey:@"currentSpell"] valueForKey:@"spellClass"] valueForKey:@"spell"];
	if([spellResistanceEdit state]==0){
		[attackRollEdit setEnabled:NO];
		[targetFailedSaveEdit setEnabled:NO];
		[diceDamageEdit2 setEnabled:NO];
		[fixedBonusDamageEdit2 setEnabled:NO];
		[totalDamageEdit2 setEnabled:NO];
		[miscBonusEdit2 setEnabled:NO];
		[diceDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																  green:0.93
																   blue:0.93
																  alpha:1.0]];
		[fixedBonusDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																		green:0.93
																		 blue:0.93
																		alpha:1.0]];
		int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
		[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];
		if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			[st setValue:[NSNumber numberWithBool:NO]
			  forKey:@"newFeatEnabled"];
		}
	}else{
		if([[spell valueForKey:@"attackRoll"] boolValue]){
			[attackRollEdit setEnabled:YES];
		}
		if ((![[spell valueForKey:@"attackRoll"] boolValue] || [attackRollEdit state]==1) && [[spell valueForKey:@"saveEffect"] intValue]>0){
			[targetFailedSaveEdit setEnabled:YES];			
		}
		if((![[spell valueForKey:@"attackRoll"] boolValue] || [attackRollEdit state]==1) &&([[spell valueForKey:@"saveEffect"] intValue]==0 || ([[spell valueForKey:@"saveEffect"] intValue]>0 && [targetFailedSaveEdit state]==1))){
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Damage"]){
				[diceDamageEdit2 setEnabled:YES];
				[fixedBonusDamageEdit2 setEnabled:YES];
				[totalDamageEdit2 setEnabled:YES];
				[miscBonusEdit2 setEnabled:YES];
				[diceDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
				[fixedBonusDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
				int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
				[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];
			}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
				[st setValue:[NSNumber numberWithBool:YES]
					  forKey:@"newFeatEnabled"];
			}
		}
	}
}
-(IBAction)passedAttackRollPressed:(id)sender{
	if([[spellTargetController selectedObjects] count]==0){
		NSLog(@"Error, in AttackRollPressed, no target selected");
		return;
	}	
	NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
	NSManagedObject *obj2=[st valueForKey:@"character"];
	NSManagedObject *spell=[[[st valueForKey:@"currentSpell"] valueForKey:@"spellClass"] valueForKey:@"spell"];
	if([attackRollEdit state]==0){
		[targetFailedSaveEdit setEnabled:NO];
		[diceDamageEdit2 setEnabled:NO];
		[fixedBonusDamageEdit2 setEnabled:NO];
		[totalDamageEdit2 setEnabled:NO];
		[miscBonusEdit2 setEnabled:NO];
		[diceDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																  green:0.93
																   blue:0.93
																  alpha:1.0]];
		[fixedBonusDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																		green:0.93
																		 blue:0.93
																		alpha:1.0]];
		int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
		[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];
		if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
			[st setValue:[NSNumber numberWithBool:NO]
				  forKey:@"newFeatEnabled"];
		}
	}else{
		if ([[spell valueForKey:@"saveEffect"] intValue]>0){
			[targetFailedSaveEdit setEnabled:YES];
		}
		if([[spell valueForKey:@"saveEffect"] intValue]==0 || ([[spell valueForKey:@"saveEffect"] intValue]>0 && [targetFailedSaveEdit state]==1)){
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Damage"]){			
				[diceDamageEdit2 setEnabled:YES];
				[fixedBonusDamageEdit2 setEnabled:YES];
				[totalDamageEdit2 setEnabled:YES];
				[miscBonusEdit2 setEnabled:YES];
				[diceDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
				[fixedBonusDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
				int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
				[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];
			}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
				[st setValue:[NSNumber numberWithBool:YES]
					  forKey:@"newFeatEnabled"];
			}
		}
	}	
}
-(IBAction)targetHasFailedSavingThrowPressed:(id)sender{
	if([[spellTargetController selectedObjects] count]==0){
		NSLog(@"Error, in SavingThrowPressed, no target selected");
		return;
	}	
	NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
	NSManagedObject *obj2=[st valueForKey:@"character"];
	NSManagedObject *spell=[[[st valueForKey:@"currentSpell"] valueForKey:@"spellClass"] valueForKey:@"spell"];
	if([targetFailedSaveEdit state]==0){
		if([[spell valueForKey:@"saveEffect"] intValue]==1){
			//halve damage.
			[diceDamageEdit2 setIntValue:[diceDamageEdit2 intValue]/2];
			[fixedBonusDamageEdit2 setIntValue:[fixedBonusDamageEdit2 intValue]/2];
			[self addUpDamageEdit2:nil];
		}else{
			[diceDamageEdit2 setEnabled:NO];
			[fixedBonusDamageEdit2 setEnabled:NO];
			[totalDamageEdit2 setEnabled:NO];
			[miscBonusEdit2 setEnabled:NO];
			[diceDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																	  green:0.93
																	   blue:0.93
																	  alpha:1.0]];
			[fixedBonusDamageEdit2 setBackgroundColor:[NSColor colorWithDeviceRed:0.93
																			green:0.93
																			 blue:0.93
																			alpha:1.0]];
			int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
			[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP]];	
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
				[st setValue:[NSNumber numberWithBool:NO]
					  forKey:@"newFeatEnabled"];
			}
		}
	}else{
		if([[spell valueForKey:@"saveEffect"] intValue]==1){
			//double damage.
			[diceDamageEdit2 setIntValue:[diceDamageEdit2 intValue]*2];
			[fixedBonusDamageEdit2 setIntValue:[fixedBonusDamageEdit2 intValue]*2];
			[self addUpDamageEdit2:nil];
		}else{
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Damage"]){
				[diceDamageEdit2 setEnabled:YES];
				[fixedBonusDamageEdit2 setEnabled:YES];
				[totalDamageEdit2 setEnabled:YES];
				[miscBonusEdit2 setEnabled:YES];
				[diceDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
				[fixedBonusDamageEdit2 setBackgroundColor:[NSColor whiteColor]];
				int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
				[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-[totalDamageEdit2 intValue]]];
			}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
				[st setValue:[NSNumber numberWithBool:YES]
					  forKey:@"newFeatEnabled"];
			}
		}
	}	
}
-(IBAction)addUpDamageEdit2:(id)sender{
	if([[spellTargetController selectedObjects] count]==0){
		NSLog(@"Error, in AddUpDamage2, no target selected");
		return;
	}	
	NSManagedObject *st=[[spellTargetController selectedObjects] objectAtIndex:0];
	int total1=[diceDamageEdit2 intValue]+[fixedBonusDamageEdit2 intValue];
	NSManagedObject *spell=[[[st valueForKey:@"currentSpell"] valueForKey:@"spellClass"] valueForKey:@"spell"];
	NSManagedObject *obj2=[st valueForKey:@"character"];
	int total2=[self checkForImmunityOnCharacter:obj2
								  withDamageType:[spell valueForKey:@"damageType"]
								  withWeaponPlus:-1
									  withDamage:total1];
	int misc=total2-total1;
	[miscBonusEdit2 setIntValue:misc];
	[totalDamageEdit2 setIntValue:total2];
	[st setValue:[NSNumber numberWithInt:total2]
		  forKey:@"newTotalDamage"];
	//now setup string.
	int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[st valueForKey:@"totalDamage"] intValue];
	[targetHPLeftEdit2 setStringValue:[NSString stringWithFormat:@"%@ now has %d hp.",[obj2 valueForKey:@"name"],preAttackHP-total2]];
	
}
-(IBAction)closeEditSheet:(id)sender{
	if([[sender window] isEqualTo:editSheet]){
		[editSheet orderOut:self];
		if([[sender title] isEqualToString:@"Continue"]){
			[NSApp endSheet:editSheet returnCode:0];
		}else{
			[NSApp endSheet:editSheet returnCode:1];
		}
	}else{
		[editSheet2 orderOut:self];
		if([[sender title] isEqualToString:@"Continue"]){
			[NSApp endSheet:editSheet2 returnCode:-1];
		}else{
			[NSApp endSheet:editSheet2 returnCode:1];
		}
	}
}
-(void)editSheetDidEnd:(NSWindow *)sheet
			returnCode:(int)code
		   contextInfo:(NSManagedObject *)currentEvent{
	if(code==0){
		NSString *message;
		NSManagedObject *obj=[currentEvent valueForKey:@"caster"];
		NSManagedObject *obj2=[currentEvent valueForKey:@"target"];
		int preAttackHP=[[obj2 valueForKey:@"currentHP"] intValue]+[[currentEvent valueForKey:@"totalDamage"] intValue];
		[obj2 setValue:[NSNumber numberWithInt:preAttackHP]
				forKey:@"currentHP"];
		if([hitTargetEdit state]){
			//now hits.
			[currentEvent setValue:[NSNumber numberWithInt:[diceDamageEdit intValue]]
							forKey:@"diceDamage"];
			[currentEvent setValue:[NSNumber numberWithInt:[fixedBonusDamageEdit intValue]]
							forKey:@"bonusDamage"];
			[currentEvent setValue:[NSNumber numberWithInt:[bonusDiceDamageEdit intValue]]
							forKey:@"bonusDieDamage"];
			int total=[totalDamageEdit intValue];
			[currentEvent setValue:[NSNumber numberWithInt:total]
							forKey:@"totalDamage"];
			[obj2 setValue:[NSNumber numberWithInt:preAttackHP-total]
					forKey:@"currentHP"];
			if([criticalHitEdit state]){
				message=[NSString stringWithFormat:@"%@ has had a critical hit on %@ doing %d damage, taking %@ to %d hit points.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],total,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
			}else{
				message=[NSString stringWithFormat:@"%@ has hit %@ doing %d damage, taking %@ to %d hit points.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"],total,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
			}
		}else{
			message=[NSString stringWithFormat:@"%@ has tried to attack %@ and has missed.",[obj valueForKey:@"name"],[obj2 valueForKey:@"name"]];
		}
		[currentEvent setValue:message
						forKey:@"resultMessage"];
	}else if(code==-1){
		//NSLog(@"spell");
		NSMutableString *message=[NSMutableString stringWithCapacity:10];
		NSManagedObject *obj=[currentEvent valueForKey:@"caster"];
		NSManagedObject *spell=[[currentEvent valueForKey:@"spellClass"] valueForKey:@"spell"];
		//check if arcane spell failure is passed.
		BOOL shouldResetDamage=NO;
		if([arcaneSpellFailureEdit state]==0 && [arcaneSpellFailureEdit isEnabled]){
			[message setString:[NSString stringWithFormat:@"%@ has failed to cast the spell %@ due to arcane spell failure.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
			shouldResetDamage=YES;
		}else if([concentrationCheckEdit state]==0){
			[message setString:[NSString stringWithFormat:@"%@ has failed a concentration check on the spell %@",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
			shouldResetDamage=YES;
		}else if(![[currentEvent valueForKey:@"originalCasting"] boolValue]){
			[message setString:[NSString stringWithFormat:@"%@'s spell %@ is still active.",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
		}else{
			[message setString:[NSString stringWithFormat:@"%@ has cast the spell %@",[obj valueForKey:@"name"],[spell valueForKey:@"name"]]];
		}
		NSArray *spellTargets=[spellTargetController arrangedObjects];
		int i;
		for(i=0;i<[spellTargets count];i++){
			//NSLog(@"spellTargets1");
			NSManagedObject *spellTarget=[spellTargets objectAtIndex:i];
			NSManagedObject *obj2=[spellTarget valueForKey:@"character"];
			if([[spell valueForKey:@"subtype"] isEqualToString:@"Healing"]){
				[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"currentHP"] intValue]-[[spellTarget valueForKey:@"totalDamage"] intValue]]
						forKey:@"currentHP"];
			}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Damage"]){
				[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"currentHP"] intValue]+[[spellTarget valueForKey:@"totalDamage"] intValue]]
						forKey:@"currentHP"];
			}
		}
		for(i=0;i<[spellTargets count];i++){
			//NSLog(@"spellTargets2");
			NSManagedObject *spellTarget=[spellTargets objectAtIndex:i];
			NSManagedObject *obj2=[spellTarget valueForKey:@"character"];
			if(!shouldResetDamage){
				//check SR.
				if([spellResistanceEdit isEnabled] && [spellResistanceEdit state]==0){
					[message appendFormat:@"\n%@ has failed to overcome the spell resistance of %@.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"]];
					shouldResetDamage=YES;
				}else if([attackRollEdit isEnabled] && [attackRollEdit state]==0){
					[message appendFormat:@"\n%@ has failed to hit %@ with the spell.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"]];
					shouldResetDamage=YES;
				}else if([targetFailedSaveEdit isEnabled] && [targetFailedSaveEdit state]==0){
					if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
						[message appendFormat:@"\n%@ has passed a saving throw against the spell and is unaffected.",[obj2 valueForKey:@"name"]];
						shouldResetDamage=YES;
					}
				}
			}
			if(shouldResetDamage){
				NSLog(@"damage should reset");
				if([[spell valueForKey:@"subtype"] isEqualToString:@"Damage"]){
					[spellTarget setValue:[NSNumber numberWithInt:0]
								   forKey:@"totalDamage"];
					[spellTarget setValue:[NSNumber numberWithInt:0]
								   forKey:@"bonusDamage"];
					[spellTarget setValue:[NSNumber numberWithInt:0]
								   forKey:@"diceDamage"];
				}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
					//NSLog(@"a feat");
					//NSLog(@"fe=%d, nfe=%d",[[spellTarget valueForKey:@"featEnabled"] intValue],[[spellTarget valueForKey:@"newFeatEnabled"] intValue]);
					if([[spellTarget valueForKey:@"featEnabled"] boolValue]){
						//NSLog(@"disabling feat properly");
						[FeatActions processFeat:spell
										forKeyNo:1
										  onChar:obj2
										forwards:NO];
						[FeatActions processFeat:spell
										forKeyNo:2
										  onChar:obj2
										forwards:NO];
						[FeatActions processFeat:spell
										forKeyNo:3
										  onChar:obj2
										forwards:NO];
						[FeatActions processFeat:spell
										forKeyNo:4
										  onChar:obj2
										forwards:NO];
					}
				}
			}else{
				int hpLost=[[spellTarget valueForKey:@"newTotalDamage"] intValue];
				if([[spell valueForKey:@"subtype"] isEqualToString:@"Healing"]){
					//healing.
					//check not over full hp.
					if([[obj2 valueForKey:@"maxHP"] intValue]-[[obj2 valueForKey:@"currentHP"] intValue]<hpLost){
						[obj2 setValue:[obj2 valueForKey:@"maxHP"]
								forKey:@"currentHP"];
						[message appendFormat:@"\n%@ has healed %@ to full health.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"]];
					}else{
						[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"currentHP"] intValue]+hpLost]
								forKey:@"currentHP"];
						[message appendFormat:@"%@ has healed %@ by %d hit points.",[[AbilityChanged getGenderOfCharacter:obj] capitalizedString],[obj2 valueForKey:@"name"],[[spellTarget valueForKey:@"newTotalDamage"] intValue]];
					}
				}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Damage"]){
					[obj2 setValue:[NSNumber numberWithInt:[[obj2 valueForKey:@"currentHP"] intValue]-hpLost]
							forKey:@"currentHP"];
					int damage=[[spellTarget valueForKey:@"newTotalDamage"] intValue];
					//NSLog(@"damage=%d",damage);
					[message appendFormat:@"\n%@",[obj2 valueForKey:@"name"]];
					int savePassed=-1;
					if([enableSThrow transformedValue:spellTarget]){
						if([[spellTarget valueForKey:@"failsSavingThrow"] boolValue]){
							savePassed=0;
						}else{
							savePassed=1;
						}
					}
					if([[spell valueForKey:@"attackRoll"] boolValue]){
						[message appendString:@" was hit and"];
						if(savePassed==0){
							[message appendString:@" but"];
						}else if(savePassed==1){
							[message appendString:@" and"];
						}
					}
					if(savePassed==-1){
						if(damage==0){
							[message appendFormat:@" has suffered no damage and still has %d hit points.",[[obj2 valueForKey:@"currentHP"] intValue]];
						}else{
							[message appendFormat:@" has suffered %d damage taking %@ to %d hit points.",damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
						}
					}else if(savePassed==1){
						[message appendString:@" has passed a saving throw,"];
						if(damage==0){
							[message appendFormat:@" as a result %@ has suffered no damage and still has %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
						}else{
							[message appendFormat:@" As a result %@ has suffered %d damage taking %@ to %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
						}
					}else{
						[message appendString:@" has failed a saving throw."];
						if(damage==0){
							[message appendFormat:@" As a result %@ has suffered no damage and still has %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
						}else{
							[message appendFormat:@" As a result %@ has suffered %d damage taking %@ to %d hit points.",[AbilityChanged getGenderOfCharacter:obj2],damage,[AbilityChanged getTPSGenderOfCharacter:obj2],[[obj2 valueForKey:@"currentHP"] intValue]];
						}
					}
					[spellTarget setValue:[spellTarget valueForKey:@"newTotalDamage"]
								   forKey:@"totalDamage"];
					[spellTarget setValue:[spellTarget valueForKey:@"newBonusDamage"]
								   forKey:@"bonusDamage"];
					[spellTarget setValue:[spellTarget valueForKey:@"newDiceDamage"]
								   forKey:@"diceDamage"];
				}else if([[spell valueForKey:@"subtype"] isEqualToString:@"Feat"]){
					[message appendFormat:@"\nThis causes the affect:%@",[spell valueForKey:@"featDescription"]];
					int savePassed=-1;
					//NSLog(@"spellTarget=%@
					int enabledSThrow=[[enableSThrow transformedValue:spellTarget] intValue];
					if(enabledSThrow){
						if([[spellTarget valueForKey:@"failsSavingThrow"] boolValue]){
							savePassed=0;
						}else{
							savePassed=1;
						}
					}
					//NSLog(@"fe=%d, nfe=%d",[[spellTarget valueForKey:@"featEnabled"] intValue],[[spellTarget valueForKey:@"newFeatEnabled"] intValue]);
					if([[spellTarget valueForKey:@"featEnabled"] boolValue] && ![[spellTarget valueForKey:@"newFeatEnabled"] boolValue]){
						//NSLog(@"disabling feat properly");
						[FeatActions processFeat:spell
										forKeyNo:1
										  onChar:obj2
										forwards:NO];
						[FeatActions processFeat:spell
										forKeyNo:2
										  onChar:obj2
										forwards:NO];
						[FeatActions processFeat:spell
										forKeyNo:3
										  onChar:obj2
										forwards:NO];
						[FeatActions processFeat:spell
										forKeyNo:4
										  onChar:obj2
										forwards:NO];
					}else if(![[spellTarget valueForKey:@"featEnabled"] boolValue] && [[spellTarget valueForKey:@"newFeatEnabled"] boolValue]){
						//NSLog(@"enabling feat properly");
						[FeatActions processFeat:spell
										forKeyNo:1
										  onChar:obj2
										forwards:YES];
						[FeatActions processFeat:spell
										forKeyNo:2
										  onChar:obj2
										forwards:YES];
						[FeatActions processFeat:spell
										forKeyNo:3
										  onChar:obj2
										forwards:YES];
						[FeatActions processFeat:spell
										forKeyNo:4
										  onChar:obj2
										forwards:YES];						
					}
					//NSLog(@"savePassed=%d",savePassed);
					if(savePassed==1){
						[message appendFormat:@"\n%@ has passed a saving throw against the spell and is unaffected.",[obj2 valueForKey:@"name"]];
					}else if(savePassed==-1){
						[message appendFormat:@"\n%@ has been affected by the spell.",[obj2 valueForKey:@"name"]];
					}else{
						[message appendFormat:@"\n%@ has failed a saving throw and has been affected by the spell.",[obj2 valueForKey:@"name"]];
					}
				}
			}
		}
		//NSLog(@"ding dong, message=%@",message);
		[currentEvent setValue:message
						forKey:@"resultMessage"];
	}
	//reprocess stuff.
	[self setupBattleDisplayWithMessage:nil];
}
-(void)alertFromEventDidEnd:(NSWindow *)sheet
			  returnCode:(int)code
			 contextInfo:(void *)contextInfo{
	[self setupBattleDisplayWithMessage:nil];
}
-(void)alertFromConcCheckDidEnd:(NSWindow *)sheet
					 returnCode:(int)code
					activeEvent:(NSManagedObject *)event{
	if(code==NSAlertDefaultReturn){
		//add one to concentration and time the spell lasts for counter.
		[event setValue:[NSNumber numberWithInt:[[event valueForKey:@"lastsUntilRound"] intValue]+1]
				 forKey:@"lastsUntilRound"];
		[event setValue:[NSNumber numberWithInt:[[event valueForKey:@"hasConcentratedFor"] intValue]+1]
				 forKey:@"hasConcentratedFor"];
		[[event valueForKey:@"caster"] setValue:[NSNumber numberWithInt:0]
										 forKey:@"attacksLeftThisRound"];
	}else{
		[event setValue:[NSNumber numberWithBool:NO]
				 forKey:@"isConcentrating"];
	}
	NSString *message=[self checkTheActiveSpell:event];
	//do nothing if message is nil as proper target sheet shown.
	if(message!=nil){
		[self setupBattleDisplayWithMessage:message];
	}
}
#pragma mark - 
#pragma mark Dealloc
#pragma mark 
-(void)dealloc{
	if(charactersSpellClasses!=nil)
		[charactersSpellClasses release];
	if(surprisedCharactersList!=nil)
		[surprisedCharactersList release];
	[super dealloc];
}
@end